<classpathentry kind="var" path="TOMCAT_LIBS_BASE/tomcat7-deps/dbcp/tomcat-dbcp.jar" sourcepath="/TOMCAT_LIBS_BASE/tomcat6-deps/dbcp/src/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="includes/h2/bin/h2-1.2.129.jar"/>
- <classpathentry combineaccessrules="false" kind="src" path="/tomcat-trunk"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/tomcat-7.0.x"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<target name="javadoc" depends="prepare">
<xslt basedir="${tomcat.pool}/doc"
- destdir="${basedir}/java/org/apache/tomcat/jdbc/pool"
+ destdir="${basedir}/src/main/java/org/apache/tomcat/jdbc/pool"
extension=".html"
style="${basedir}/doc/package.xsl"
excludes="build.xml"
<param name="relative-path" expression="http://tomcat.apache.org/tomcat-6.0-doc"/>
<param name="apache-logo" expression="/images/asf-logo.gif"/>
</xslt>
- <move tofile="${basedir}/java/org/apache/tomcat/jdbc/pool/package.html"
- file="${basedir}/java/org/apache/tomcat/jdbc/pool/jdbc-pool.html"/>
- <javadoc sourcepath="${basedir}/java" destdir="${tomcat.api}" verbose="false"
+ <move tofile="${basedir}/src/main/java/org/apache/tomcat/jdbc/pool/package.html"
+ file="${basedir}/src/main/java/org/apache/tomcat/jdbc/pool/jdbc-pool.html"/>
+ <javadoc sourcepath="${basedir}/src/main/java" destdir="${tomcat.api}" verbose="false"
link="http://java.sun.com/javase/6/docs/api/">
<classpath refid="tomcat.jdbc.classpath"/>
</javadoc>
<fileset dir="${tomcat.api}"/>
<fileset refid="license.notice"/>
</jar>
- <delete file="${basedir}/java/org/apache/tomcat/jdbc/pool/package.html"/>
+ <delete file="${basedir}/src/main/java/org/apache/tomcat/jdbc/pool/package.html"/>
</target>
<target name="build" depends="prepare,download">
<mkdir dir="${tomcat.pool}"/>
<!-- compile org.apache.tomcat.jdbc-->
- <javac srcdir="${basedir}/java" destdir="${tomcat.classes}"
+ <javac srcdir="${basedir}/src/main/java" destdir="${tomcat.classes}"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
source="${compile.source}"
<fileset dir="${tomcat.classes}">
<include name="org/apache/tomcat/jdbc/**" />
</fileset>
- <fileset dir="${basedir}/java">
+ <fileset dir="${basedir}/src/main/java">
<include name="org/apache/tomcat/jdbc/**/*.xml" />
</fileset>
<fileset refid="license.notice"/>
<!-- connection pool source file-->
<jar jarfile="${tomcat-jdbc-src.jar}" update="true">
- <fileset dir="${basedir}/java">
+ <fileset dir="${basedir}/src/main/java">
<include name="org/apache/tomcat/jdbc/**" />
</fileset>
<fileset refid="license.notice"/>
<target name="build-test" depends="prepare, build, download-test">
<mkdir dir="${tomcat.pool}"/>
<!-- compile org.apache.tomcat.jdbc-->
- <javac srcdir="${basedir}/test" destdir="${tomcat.testclasses}"
+ <javac srcdir="${basedir}/src/test/java" destdir="${tomcat.testclasses}"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
source="${compile.source}"
<fileset dir="${tomcat.testclasses}">
<include name="org/apache/tomcat/jdbc/**" />
</fileset>
- <fileset dir="${basedir}/test">
+ <fileset dir="${basedir}/src/test/java">
<include name="org/apache/tomcat/jdbc/**/*.xml" />
</fileset>
<fileset refid="license.notice"/>
</jar>
<jar jarfile="${tomcat-jdbc-test-src.jar}" update="true">
- <fileset dir="${basedir}/test">
+ <fileset dir="${basedir}/src/test/java">
<include name="org/apache/tomcat/jdbc/**" />
</fileset>
<fileset refid="license.notice"/>
<classpath refid="tomcat.jdbc.classpath"/>
<classpath refid="test.classpath"/>
<batchtest fork="yes" todir="${tomcat.testclasses}">
- <fileset dir="${basedir}/test">
+ <fileset dir="${basedir}/src/test/java">
<include name="**/CreateTestTable*"/>
</fileset>
</batchtest>
<classpath refid="tomcat.jdbc.classpath"/>
<classpath refid="test.classpath"/>
<batchtest fork="yes" todir="${tomcat.testclasses}">
- <fileset dir="${basedir}/test">
+ <fileset dir="${basedir}/src/test/java">
<include name="org/apache/tomcat/jdbc/test/*CheckOutThreadTest*.java"/>
<include name="org/apache/tomcat/jdbc/test/FairnessTest*.java"/>
<exclude name="**/CreateTestTable*"/>
<classpath refid="tomcat.jdbc.classpath"/>
<classpath refid="test.classpath"/>
<batchtest fork="yes" todir="${tomcat.testclasses}">
- <fileset dir="${basedir}/test">
+ <fileset dir="${basedir}/src/test/java">
<include name="org/apache/tomcat/jdbc/test/*Test*.java"/>
<exclude name="org/apache/tomcat/jdbc/test/*CheckOutThreadTest*.java"/>
<exclude name="**/CreateTestTable*"/>
<classpath refid="tomcat.jdbc.classpath"/>
<classpath refid="test.classpath"/>
<batchtest fork="yes" todir="${tomcat.testclasses}">
- <fileset dir="${basedir}/test">
+ <fileset dir="${basedir}/src/test/java">
<include name="org/apache/tomcat/jdbc/test/*${test}*.java"/>
<exclude name="**/CreateTestTable*"/>
<exclude name="**/DefaultTestCase*"/>
+++ /dev/null
-/*
- * 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.naming;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Enumeration;
-import java.util.Hashtable;
-
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.RefAddr;
-import javax.naming.Reference;
-import javax.naming.spi.ObjectFactory;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-/**
- * Simple way of configuring generic resources by using reflection.
- * Example usage:
- * <pre><code>
- * <Resource factory="org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory"
- * name="jdbc/test"
- * type="org.apache.derby.jdbc.ClientXADataSource"
- * databaseName="sample"
- * createDatabase="create"
- * serverName="localhost"
- * port="1527"/>
- * </code></pre>
- *
- */
-public class GenericNamingResourcesFactory implements ObjectFactory {
- private static final Log log = LogFactory.getLog(GenericNamingResourcesFactory.class);
-
- public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
- if ((obj == null) || !(obj instanceof Reference)) {
- return null;
- }
- Reference ref = (Reference) obj;
- Enumeration<RefAddr> refs = ref.getAll();
-
- String type = ref.getClassName();
- Object o = Class.forName(type).newInstance();
-
- while (refs.hasMoreElements()) {
- RefAddr addr = refs.nextElement();
- String param = addr.getType();
- String value = null;
- if (addr.getContent()!=null) {
- value = addr.getContent().toString();
- }
- if (setProperty(o, param, value,false)) {
-
- } else {
- log.debug("Property not configured["+param+"]. No setter found on["+o+"].");
- }
- }
- return o;
- }
-
- public static boolean setProperty(Object o, String name, String value,boolean invokeSetProperty) {
- if (log.isDebugEnabled())
- log.debug("IntrospectionUtils: setProperty(" +
- o.getClass() + " " + name + "=" + value + ")");
-
- String setter = "set" + capitalize(name);
-
- try {
- Method methods[] = o.getClass().getMethods();
- Method setPropertyMethodVoid = null;
- Method setPropertyMethodBool = null;
-
- // First, the ideal case - a setFoo( String ) method
- for (int i = 0; i < methods.length; i++) {
- Class<?> paramT[] = methods[i].getParameterTypes();
- if (setter.equals(methods[i].getName()) && paramT.length == 1
- && "java.lang.String".equals(paramT[0].getName())) {
-
- methods[i].invoke(o, new Object[] { value });
- return true;
- }
- }
-
- // Try a setFoo ( int ) or ( boolean )
- for (int i = 0; i < methods.length; i++) {
- boolean ok = true;
- if (setter.equals(methods[i].getName())
- && methods[i].getParameterTypes().length == 1) {
-
- // match - find the type and invoke it
- Class<?> paramType = methods[i].getParameterTypes()[0];
- Object params[] = new Object[1];
-
- // Try a setFoo ( int )
- if ("java.lang.Integer".equals(paramType.getName())
- || "int".equals(paramType.getName())) {
- try {
- params[0] = new Integer(value);
- } catch (NumberFormatException ex) {
- ok = false;
- }
- // Try a setFoo ( long )
- }else if ("java.lang.Long".equals(paramType.getName())
- || "long".equals(paramType.getName())) {
- try {
- params[0] = new Long(value);
- } catch (NumberFormatException ex) {
- ok = false;
- }
-
- // Try a setFoo ( boolean )
- } else if ("java.lang.Boolean".equals(paramType.getName())
- || "boolean".equals(paramType.getName())) {
- params[0] = new Boolean(value);
-
- // Try a setFoo ( InetAddress )
- } else if ("java.net.InetAddress".equals(paramType
- .getName())) {
- try {
- params[0] = InetAddress.getByName(value);
- } catch (UnknownHostException exc) {
- if (log.isDebugEnabled())
- log.debug("IntrospectionUtils: Unable to resolve host name:" + value);
- ok = false;
- }
-
- // Unknown type
- } else {
- if (log.isDebugEnabled())
- log.debug("IntrospectionUtils: Unknown type " +
- paramType.getName());
- }
-
- if (ok) {
- methods[i].invoke(o, params);
- return true;
- }
- }
-
- // save "setProperty" for later
- if ("setProperty".equals(methods[i].getName())) {
- if (methods[i].getReturnType()==Boolean.TYPE){
- setPropertyMethodBool = methods[i];
- }else {
- setPropertyMethodVoid = methods[i];
- }
-
- }
- }
-
- // Ok, no setXXX found, try a setProperty("name", "value")
- if (setPropertyMethodBool != null || setPropertyMethodVoid != null) {
- Object params[] = new Object[2];
- params[0] = name;
- params[1] = value;
- if (setPropertyMethodBool != null) {
- try {
- return (Boolean) setPropertyMethodBool.invoke(o, params);
- }catch (IllegalArgumentException biae) {
- //the boolean method had the wrong
- //parameter types. lets try the other
- if (setPropertyMethodVoid!=null) {
- setPropertyMethodVoid.invoke(o, params);
- return true;
- }else {
- throw biae;
- }
- }
- } else {
- setPropertyMethodVoid.invoke(o, params);
- return true;
- }
- }
-
- } catch (IllegalArgumentException ex2) {
- log.warn("IAE " + o + " " + name + " " + value, ex2);
- } catch (SecurityException ex1) {
- if (log.isDebugEnabled())
- log.debug("IntrospectionUtils: SecurityException for " +
- o.getClass() + " " + name + "=" + value + ")", ex1);
- } catch (IllegalAccessException iae) {
- if (log.isDebugEnabled())
- log.debug("IntrospectionUtils: IllegalAccessException for " +
- o.getClass() + " " + name + "=" + value + ")", iae);
- } catch (InvocationTargetException ie) {
- if (log.isDebugEnabled())
- log.debug("IntrospectionUtils: InvocationTargetException for " +
- o.getClass() + " " + name + "=" + value + ")", ie);
- }
- return false;
- }
-
- public static String capitalize(String name) {
- if (name == null || name.length() == 0) {
- return name;
- }
- char chars[] = name.toCharArray();
- chars[0] = Character.toUpperCase(chars[0]);
- return new String(chars);
- }
-
-}
+++ /dev/null
-/*
- * 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.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.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-
-/**
- * Implementation of simple connection pool.
- * The ConnectionPool uses a {@link PoolProperties} object for storing all the meta information about the connection pool.
- * As the underlying implementation, the connection pool uses {@link java.util.concurrent.BlockingQueue} to store active and idle connections.
- * A custom implementation of a fair {@link FairBlockingQueue} blocking queue is provided with the connection pool itself.
- * @author Filip Hanik
- * @version 1.0
- */
-
-public class ConnectionPool {
- /**
- * Prefix type for JMX registration
- */
- public static final String POOL_JMX_TYPE_PREFIX = "tomcat.jdbc:type=";
-
- /**
- * Logger
- */
- private static final Log log = LogFactory.getLog(ConnectionPool.class);
-
- //===============================================================================
- // INSTANCE/QUICK ACCESS VARIABLE
- //===============================================================================
- /**
- * Carries the size of the pool, instead of relying on a queue implementation
- * that usually iterates over to get an exact count
- */
- private AtomicInteger size = new AtomicInteger(0);
-
- /**
- * All the information about the connection pool
- * These are the properties the pool got instantiated with
- */
- private PoolConfiguration poolProperties;
-
- /**
- * Contains all the connections that are in use
- * TODO - this shouldn't be a blocking queue, simply a list to hold our objects
- */
- private BlockingQueue<PooledConnection> busy;
-
- /**
- * Contains all the idle connections
- */
- private BlockingQueue<PooledConnection> idle;
-
- /**
- * The thread that is responsible for checking abandoned and idle threads
- */
- private volatile PoolCleaner poolCleaner;
-
- /**
- * Pool closed flag
- */
- private volatile boolean closed = false;
-
- /**
- * Since newProxyInstance performs the same operation, over and over
- * again, it is much more optimized if we simply store the constructor ourselves.
- */
- private Constructor<?> proxyClassConstructor;
-
- /**
- * Executor service used to cancel Futures
- */
- private ThreadPoolExecutor cancellator = new ThreadPoolExecutor(0,1,1000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
-
- /**
- * reference to the JMX mbean
- */
- protected org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool = null;
-
- /**
- * counter to track how many threads are waiting for a connection
- */
- private AtomicInteger waitcount = new AtomicInteger(0);
-
- //===============================================================================
- // PUBLIC METHODS
- //===============================================================================
-
- /**
- * Instantiate a connection pool. This will create connections if initialSize is larger than 0.
- * The {@link PoolProperties} should not be reused for another connection pool.
- * @param prop PoolProperties - all the properties for this connection pool
- * @throws SQLException
- */
- public ConnectionPool(PoolConfiguration prop) throws SQLException {
- //setup quick access variables and pools
- init(prop);
- }
-
-
- /**
- * Retrieves a Connection future. If a connection is not available, one can block using future.get()
- * until a connection has become available.
- * If a connection is not retrieved, the Future must be cancelled in order for the connection to be returned
- * to the pool.
- * @return a Future containing a reference to the connection or the future connection
- * @throws SQLException
- */
- public Future<Connection> getConnectionAsync() throws SQLException {
- try {
- PooledConnection pc = borrowConnection(0, null, null);
- if (pc!=null) {
- return new ConnectionFuture(pc);
- }
- }catch (SQLException x) {
- if (x.getMessage().indexOf("NoWait")<0) {
- throw x;
- }
- }
- //we can only retrieve a future if the underlying queue supports it.
- if (idle instanceof FairBlockingQueue<?>) {
- Future<PooledConnection> pcf = ((FairBlockingQueue<PooledConnection>)idle).pollAsync();
- return new ConnectionFuture(pcf);
- } else if (idle instanceof MultiLockFairBlockingQueue<?>) {
- Future<PooledConnection> pcf = ((MultiLockFairBlockingQueue<PooledConnection>)idle).pollAsync();
- return new ConnectionFuture(pcf);
- } else {
- throw new SQLException("Connection pool is misconfigured, doesn't support async retrieval. Set the 'fair' property to 'true'");
- }
- }
-
- /**
- * Borrows a connection from the pool. If a connection is available (in the idle queue) or the pool has not reached
- * {@link PoolProperties#maxActive maxActive} connections a connection is returned immediately.
- * If no connection is available, the pool will attempt to fetch a connection for {@link PoolProperties#maxWait maxWait} milliseconds.
- * @return Connection - a java.sql.Connection/javax.sql.PooledConnection reflection proxy, wrapping the underlying object.
- * @throws SQLException - if the wait times out or a failure occurs creating a connection
- */
- public Connection getConnection() throws SQLException {
- //check out a connection
- PooledConnection con = borrowConnection(-1,null,null);
- return setupConnection(con);
- }
-
-
- /**
- * Borrows a connection from the pool. If a connection is available (in the
- * idle queue) or the pool has not reached {@link PoolProperties#maxActive
- * maxActive} connections a connection is returned immediately. If no
- * connection is available, the pool will attempt to fetch a connection for
- * {@link PoolProperties#maxWait maxWait} milliseconds.
- *
- * @return Connection - a java.sql.Connection/javax.sql.PooledConnection
- * reflection proxy, wrapping the underlying object.
- * @throws SQLException
- * - if the wait times out or a failure occurs creating a
- * connection
- */
- public Connection getConnection(String username, String password) throws SQLException {
- // check out a connection
- PooledConnection con = borrowConnection(-1, username, password);
- return setupConnection(con);
- }
-
- /**
- * Returns the name of this pool
- * @return String - the name of the pool
- */
- public String getName() {
- return getPoolProperties().getPoolName();
- }
-
- /**
- * Return the number of threads waiting for a connection
- * @return number of threads waiting for a connection
- */
- public int getWaitCount() {
- return waitcount.get();
- }
-
- /**
- * Returns the pool properties associated with this connection pool
- * @return PoolProperties
- *
- */
- public PoolConfiguration getPoolProperties() {
- return this.poolProperties;
- }
-
- /**
- * Returns the total size of this pool, this includes both busy and idle connections
- * @return int - number of established connections to the database
- */
- public int getSize() {
- return size.get();
- }
-
- /**
- * Returns the number of connections that are in use
- * @return int - number of established connections that are being used by the application
- */
- public int getActive() {
- return busy.size();
- }
-
- /**
- * Returns the number of idle connections
- * @return int - number of established connections not being used
- */
- 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;
- }
-
- //===============================================================================
- // PROTECTED METHODS
- //===============================================================================
-
-
- /**
- * configures a pooled connection as a proxy.
- * This Proxy implements {@link java.sql.Connection} and {@link javax.sql.PooledConnection} interfaces.
- * All calls on {@link java.sql.Connection} methods will be propagated down to the actual JDBC connection except for the
- * {@link java.sql.Connection#close()} method.
- * @param con a {@link PooledConnection} to wrap in a Proxy
- * @return a {@link java.sql.Connection} object wrapping a pooled connection.
- * @throws SQLException if an interceptor can't be configured, if the proxy can't be instantiated
- */
- protected Connection setupConnection(PooledConnection con) throws SQLException {
- //fetch previously cached interceptor proxy - one per connection
- JdbcInterceptor handler = con.getHandler();
- if (handler==null) {
- //build the proxy handler
- handler = new ProxyConnection(this,con,getPoolProperties().isUseEquals());
- //set up the interceptor chain
- PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
- for (int i=proxies.length-1; i>=0; i--) {
- try {
- //create a new instance
- JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
- //configure properties
- interceptor.setProperties(proxies[i].getProperties());
- //setup the chain
- interceptor.setNext(handler);
- //call reset
- interceptor.reset(this, con);
- //configure the last one to be held by the connection
- 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 {
- getProxyConstructor(con.getXAConnection() != null);
- //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) {
- SQLException s = new SQLException();
- s.initCause(x);
- throw s;
- }
-
- }
-
- /**
- * Creates and caches a {@link java.lang.reflect.Constructor} used to instantiate the proxy object.
- * We cache this, since the creation of a constructor is fairly slow.
- * @return constructor used to instantiate the wrapper object
- * @throws NoSuchMethodException
- */
- public Constructor<?> getProxyConstructor(boolean xa) throws NoSuchMethodException {
- //cache the constructor
- if (proxyClassConstructor == null ) {
- Class<?> proxyClass = xa ?
- Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class, javax.sql.XAConnection.class}) :
- Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class});
- proxyClassConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
- }
- return proxyClassConstructor;
- }
-
- /**
- * 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.interrupted();
- }
- if (pool.size()==0 && force && pool!=busy) pool = busy;
- }
- if (this.getPoolProperties().isJmxEnabled()) this.jmxPool = null;
- PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
- for (int i=0; i<proxies.length; i++) {
- try {
- proxies[i].getInterceptorClass().newInstance().poolClosed(this);
- }catch (Exception x) {
- log.debug("Unable to inform interceptor of pool closure.",x);
- }
- }
- } //closePool
-
-
- /**
- * Initialize the connection pool - called from the constructor
- * @param properties PoolProperties - properties used to initialize the pool with
- * @throws SQLException if initialization fails
- */
- protected void init(PoolConfiguration properties) throws SQLException {
- poolProperties = properties;
- //make space for 10 extra in case we flow over a bit
- busy = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),false);
- //busy = new FairBlockingQueue<PooledConnection>();
- //make space for 10 extra in case we flow over a bit
- if (properties.isFairQueue()) {
- idle = new FairBlockingQueue<PooledConnection>();
- //idle = new MultiLockFairBlockingQueue<PooledConnection>();
- } else {
- idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),properties.isFairQueue());
- }
-
- //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
-
- //make sure the pool is properly configured
- if (properties.getMaxActive()<1) {
- log.warn("maxActive is smaller than 1, setting maxActive to: "+PoolProperties.DEFAULT_MAX_ACTIVE);
- properties.setMaxActive(PoolProperties.DEFAULT_MAX_ACTIVE);
- }
- 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());
- }
-
- //create JMX MBean
- if (this.getPoolProperties().isJmxEnabled()) createMBean();
-
- //Parse and create an initial set of interceptors. Letting them know the pool has started.
- //These interceptors will not get any connection.
- PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
- for (int i=0; i<proxies.length; i++) {
- try {
- if (log.isDebugEnabled()) {
- log.debug("Creating interceptor instance of class:"+proxies[i].getInterceptorClass());
- }
- proxies[i].getInterceptorClass().newInstance().poolStarted(this);
- }catch (Exception x) {
- log.error("Unable to inform interceptor of pool start.",x);
- if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));
- close(true);
- SQLException ex = new SQLException();
- ex.initCause(x);
- throw ex;
- }
- }
-
- //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(0, null, null); //don't wait, should be no contention
- } //for
-
- } catch (SQLException x) {
- if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(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){/*NOOP*/}
- } //end if
- } //for
- } //catch
-
- closed = false;
- }
-
-
-//===============================================================================
-// CONNECTION POOLING IMPL LOGIC
-//===============================================================================
-
- /**
- * 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();
- String trace = con.getStackTrace();
- if (getPoolProperties().isLogAbandoned()) {
- log.warn("Connection has been abandoned " + con + ":" + trace);
- }
- if (jmxPool!=null) {
- jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_ABANDON, trace);
- }
- //release the connection
- release(con);
- } finally {
- con.unlock();
- }
- }
-
- /**
- * 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 suspect(PooledConnection con) {
- if (con == null)
- return;
- if (con.isSuspect())
- return;
- try {
- con.lock();
- String trace = con.getStackTrace();
- if (getPoolProperties().isLogAbandoned()) {
- log.warn("Connection has been marked suspect, possibly abandoned " + con + "["+(System.currentTimeMillis()-con.getTimestamp())+" ms.]:" + trace);
- }
- if (jmxPool!=null) {
- jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.SUSPECT_ABANDONED_NOTIFICATION, trace);
- }
- con.setSuspect(true);
- } 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();
- if (con.release()) {
- //counter only decremented once
- size.addAndGet(-1);
- con.setHandler(null);
- }
- } finally {
- con.unlock();
- }
- // we've asynchronously reduced the number of connections
- // we could have threads stuck in idle.poll(timeout) that will never be
- // notified
- if (waitcount.get() > 0) {
- idle.offer(create(true));
- }
- }
-
- /**
- * Thread safe way to retrieve a connection from the pool
- * @param wait - time to wait, overrides the maxWait from the properties,
- * set to -1 if you wish to use maxWait, 0 if you wish no wait time.
- * @return PooledConnection
- * @throws SQLException
- */
- private PooledConnection borrowConnection(int wait, String username, String password) 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) {
- //configure the connection and return it
- PooledConnection result = borrowConnection(now, con, username, password);
- //null should never be returned, but was in a previous impl.
- if (result!=null) return result;
- }
-
- //if we get here, see if we need to create one
- //this is not 100% accurate since it doesn't use a shared
- //atomic variable - a connection can become idle while we are creating
- //a new connection
- if (size.get() < getPoolProperties().getMaxActive()) {
- //atomic duplicate check
- if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
- //if we got here, two threads passed through the first if
- size.decrementAndGet();
- } else {
- //create a connection, we're below the limit
- return createConnection(now, con, username, password);
- }
- } //end if
-
- //calculate wait time for this iteration
- long maxWait = wait;
- //if the passed in wait time is -1, means we should use the pool property value
- if (wait==-1) {
- maxWait = (getPoolProperties().getMaxWait()<=0)?Long.MAX_VALUE:getPoolProperties().getMaxWait();
- }
-
- long timetowait = Math.max(0, maxWait - (System.currentTimeMillis() - now));
- waitcount.incrementAndGet();
- try {
- //retrieve an existing connection
- con = idle.poll(timetowait, TimeUnit.MILLISECONDS);
- } catch (InterruptedException ex) {
- Thread.interrupted();//clear the flag, and bail out
- SQLException sx = new SQLException("Pool wait interrupted.");
- sx.initCause(ex);
- throw sx;
- } finally {
- waitcount.decrementAndGet();
- }
- if (maxWait==0 && con == null) { //no wait, return one if we have one
- throw new SQLException("[" + Thread.currentThread().getName()+"] " +
- "NoWait: Pool empty. Unable to fetch a connection, none available["+busy.size()+" in use].");
- }
- //we didn't get a connection, lets see if we timed out
- if (con == null) {
- if ((System.currentTimeMillis() - now) >= maxWait) {
- throw new SQLException("[" + Thread.currentThread().getName()+"] " +
- "Timeout: 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
- }
-
- /**
- * Creates a JDBC connection and tries to connect to the database.
- * @param now timestamp of when this was called
- * @param notUsed Argument not used
- * @return a PooledConnection that has been connected
- * @throws SQLException
- */
- protected PooledConnection createConnection(long now, PooledConnection notUsed, String username, String password) throws SQLException {
- //no connections where available we'll create one
- PooledConnection con = create(false);
- if (username!=null) con.getAttributes().put(con.PROP_USER, username);
- if (password!=null) con.getAttributes().put(con.PROP_PASSWORD, password);
- boolean error = false;
- try {
- //connect and validate the connection
- con.lock();
- 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());
- }
- if (!busy.offer(con)) {
- log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
- }
- return con;
- } else {
- //validation failed, make sure we disconnect
- //and clean up
- error =true;
- } //end if
- } catch (Exception e) {
- error = true;
- if (log.isDebugEnabled())
- log.debug("Unable to create a new JDBC connection.", e);
- if (e instanceof SQLException) {
- throw (SQLException)e;
- } else {
- SQLException ex = new SQLException(e.getMessage());
- ex.initCause(e);
- throw ex;
- }
- } finally {
- // con can never be null here
- if (error ) {
- release(con);
- }
- con.unlock();
- }//catch
- return null;
- }
-
- /**
- * Validates and configures a previously idle connection
- * @param now - timestamp
- * @param con - the connection to validate and configure
- * @return con
- * @throws SQLException if a validation error happens
- */
- protected PooledConnection borrowConnection(long now, PooledConnection con, String username, String password) throws SQLException {
- //we have a connection, lets set it up
-
- //flag to see if we need to nullify
- boolean setToNull = false;
- try {
- con.lock();
- boolean usercheck = con.checkUser(username, password);
-
- if (con.isReleased()) {
- return null;
- }
-
- if (!con.isDiscarded() && !con.isInitialized()) {
- //attempt to connect
- con.connect();
- }
-
- if (usercheck) {
- if ((!con.isDiscarded()) && 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;
- }
- }
- //if we reached here, that means the connection
- //is either has another principal, is discarded or validation failed.
- //we will make one more attempt
- //in order to guarantee that the thread that just acquired
- //the connection shouldn't have to poll again.
- try {
- con.reconnect();
- if (con.validate(PooledConnection.VALIDATE_INIT)) {
- //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 {
- //validation failed.
- release(con);
- setToNull = true;
- throw new SQLException("Failed to validate a newly established connection.");
- }
- } catch (Exception x) {
- release(con);
- setToNull = true;
- if (x instanceof SQLException) {
- throw (SQLException)x;
- } else {
- SQLException ex = new SQLException(x.getMessage());
- ex.initCause(x);
- throw ex;
- }
- }
- } finally {
- con.unlock();
- if (setToNull) {
- con = null;
- }
- }
- }
-
- /**
- * Determines if a connection should be closed upon return to the pool.
- * @param con - the connection
- * @param action - the validation action that should be performed
- * @return true if the connection should be closed
- */
- protected boolean shouldClose(PooledConnection con, int action) {
- if (con.isDiscarded()) return true;
- if (isClosed()) return true;
- if (!con.validate(action)) return true;
- if (getPoolProperties().getMaxAge()>0 ) {
- return (System.currentTimeMillis()-con.getLastConnected()) > getPoolProperties().getMaxAge();
- } else {
- return false;
- }
- }
-
- /**
- * Returns a connection to the pool
- * If the pool is closed, the connection will be released
- * If the connection is not part of the busy queue, it will be released.
- * If {@link PoolProperties#testOnReturn} is set to true it will be validated
- * @param con PooledConnection to be returned to the pool
- */
- 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 (!shouldClose(con,PooledConnection.VALIDATE_RETURN)) {
- con.setStackTrace(null);
- con.setTimestamp(System.currentTimeMillis());
- if (((idle.size()>=poolProperties.getMaxIdle()) && !poolProperties.isPoolSweeperEnabled()) || (!idle.offer(con))) {
- if (log.isDebugEnabled()) {
- log.debug("Connection ["+con+"] will be closed and not returned to the pool, idle["+idle.size()+"]>=maxIdle["+poolProperties.getMaxIdle()+"] 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
-
- /**
- * Determines if a connection should be abandoned based on
- * {@link PoolProperties#abandonWhenPercentageFull} setting.
- * @return true if the connection should be abandoned
- */
- protected boolean shouldAbandon() {
- if (poolProperties.getAbandonWhenPercentageFull()==0) return true;
- float used = busy.size();
- float max = poolProperties.getMaxActive();
- float perc = poolProperties.getAbandonWhenPercentageFull();
- return (used/max*100f)>=perc;
- }
-
- /**
- * Iterates through all the busy connections and checks for connections that have timed out
- */
- public void checkAbandoned() {
- try {
- if (busy.size()==0) return;
- Iterator<PooledConnection> locked = busy.iterator();
- int sto = getPoolProperties().getSuspectTimeout();
- 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();
- long now = System.currentTimeMillis();
- if (shouldAbandon() && (now - time) > con.getAbandonTimeout()) {
- busy.remove(con);
- abandon(con);
- setToNull = true;
- } else if (sto > 0 && (now - time) > (sto*1000)) {
- suspect(con);
- } 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);
- }
- }
-
- /**
- * Iterates through the idle connections and resizes the idle pool based on parameters
- * {@link PoolProperties#maxIdle}, {@link PoolProperties#minIdle}, {@link PoolProperties#minEvictableIdleTimeMillis}
- */
- public void checkIdle() {
- try {
- if (idle.size()==0) return;
- 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 ((con.getReleaseTime()>0) && ((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);
- }
-
- }
-
- /**
- * Forces a validation of all idle connections if {@link PoolProperties#testWhileIdle} is set.
- */
- public void testAllIdle() {
- try {
- if (idle.size()==0) return;
- 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);
- release(con);
- }
- } finally {
- con.unlock();
- }
- } //while
- } catch (ConcurrentModificationException e) {
- log.debug("testAllIdle failed." ,e);
- } catch (Exception e) {
- log.warn("testAllIdle failed, it will be retried.",e);
- }
-
- }
-
- /**
- * Creates a stack trace representing the existing thread's current state.
- * @return a string object representing the current state.
- * TODO investigate if we simply should store {@link java.lang.Thread#getStackTrace()} elements
- */
- protected static String getThreadDump() {
- Exception x = new Exception();
- x.fillInStackTrace();
- return getStackTrace(x);
- }
-
- /**
- * Convert an exception into a String
- * @param x - the throwable
- * @return a string representing the stack trace
- */
- public static String getStackTrace(Throwable 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 (x.getMessage()!=null && x.getMessage().length()>0)? x.getMessage()+";"+result:result;
- } //end if
- }
-
-
- /**
- * Create a new pooled connection object. Not connected nor validated.
- * @return a pooled connection object
- */
- protected PooledConnection create(boolean incrementCounter) {
- if (incrementCounter) size.incrementAndGet();
- PooledConnection con = new PooledConnection(getPoolProperties(), this);
- return con;
- }
-
- /**
- * Hook to perform final actions on a pooled connection object once it has been disconnected and will be discarded
- * @param con
- */
- protected void finalize(PooledConnection con) {
- JdbcInterceptor handler = con.getHandler();
- while (handler!=null) {
- handler.reset(null, null);
- handler=handler.getNext();
- }
- }
-
- /**
- * Hook to perform final actions on a pooled connection object once it has been disconnected and will be discarded
- * @param con
- */
- protected void disconnectEvent(PooledConnection con, boolean finalizing) {
- JdbcInterceptor handler = con.getHandler();
- while (handler!=null) {
- handler.disconnected(this, con, finalizing);
- handler=handler.getNext();
- }
- }
-
- /**
- * Return the object that is potentially registered in JMX for notifications
- * @return the object implementing the {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} interface
- */
- public org.apache.tomcat.jdbc.pool.jmx.ConnectionPool getJmxPool() {
- return jmxPool;
- }
-
- /**
- * Create MBean object that can be registered.
- */
- protected void createMBean() {
- try {
- jmxPool = new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(this);
- } catch (Exception x) {
- log.warn("Unable to start JMX integration for connection pool. Instance["+getName()+"] can't be monitored.",x);
- }
- }
-
- /**
- * Tread safe wrapper around a future for the regular queue
- * This one retrieves the pooled connection object
- * and performs the initialization according to
- * interceptors and validation rules.
- * This class is thread safe and is cancellable
- * @author fhanik
- *
- */
- protected class ConnectionFuture implements Future<Connection>, Runnable {
- Future<PooledConnection> pcFuture = null;
- AtomicBoolean configured = new AtomicBoolean(false);
- CountDownLatch latch = new CountDownLatch(1);
- Connection result = null;
- SQLException cause = null;
- AtomicBoolean cancelled = new AtomicBoolean(false);
- volatile PooledConnection pc = null;
- public ConnectionFuture(Future<PooledConnection> pcf) {
- this.pcFuture = pcf;
- }
-
- public ConnectionFuture(PooledConnection pc) throws SQLException {
- this.pc = pc;
- result = ConnectionPool.this.setupConnection(pc);
- configured.set(true);
- }
- /**
- * {@inheritDoc}
- */
- public boolean cancel(boolean mayInterruptIfRunning) {
- if (pc!=null) {
- return false;
- } else if ((!cancelled.get()) && cancelled.compareAndSet(false, true)) {
- //cancel by retrieving the connection and returning it to the pool
- ConnectionPool.this.cancellator.execute(this);
- }
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- public Connection get() throws InterruptedException, ExecutionException {
- try {
- return get(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
- }catch (TimeoutException x) {
- throw new ExecutionException(x);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public Connection get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- PooledConnection pc = this.pc!=null?this.pc:pcFuture.get(timeout,unit);
- if (pc!=null) {
- if (result!=null) return result;
- if (configured.compareAndSet(false, true)) {
- try {
- pc = borrowConnection(System.currentTimeMillis(),pc, null, null);
- result = ConnectionPool.this.setupConnection(pc);
- } catch (SQLException x) {
- cause = x;
- } finally {
- latch.countDown();
- }
- } else {
- //if we reach here, another thread is configuring the actual connection
- latch.await(timeout,unit); //this shouldn't block for long
- }
- if (result==null) throw new ExecutionException(cause);
- return result;
- } else {
- return null;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isCancelled() {
- return pc==null && (pcFuture.isCancelled() || cancelled.get());
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isDone() {
- return pc!=null || pcFuture.isDone();
- }
-
- /**
- * run method to be executed when cancelled by an executor
- */
- public void run() {
- try {
- Connection con = get(); //complete this future
- con.close(); //return to the pool
- }catch (ExecutionException ex) {
- //we can ignore this
- }catch (Exception x) {
- ConnectionPool.log.error("Unable to cancel ConnectionFuture.",x);
- }
- }
-
- }
-
- protected class PoolCleaner extends Thread {
- protected ConnectionPool pool;
- protected long sleepTime;
- protected volatile boolean run = true;
- PoolCleaner(String name, ConnectionPool pool, long sleepTime) {
- super(name);
- this.setDaemon(true);
- this.pool = pool;
- this.sleepTime = sleepTime;
- if (sleepTime <= 0) {
- log.warn("Database connection pool evicter thread interval is set to 0, defaulting to 30 seconds");
- this.sleepTime = 1000 * 30;
- } else if (sleepTime < 1000) {
- log.warn("Database connection pool evicter thread interval is set to lower than 1 second.");
- }
- }
-
- @Override
- public void run() {
- while (run) {
- try {
- sleep(sleepTime);
- } catch (InterruptedException e) {
- // ignore it
- Thread.interrupted();
- continue;
- } //catch
-
- if (pool.isClosed()) {
- if (pool.getSize() <= 0) {
- run = false;
- }
- } else {
- try {
- if (pool.getPoolProperties().isRemoveAbandoned())
- pool.checkAbandoned();
- if (pool.getPoolProperties().getMinIdle()<pool.idle.size())
- pool.checkIdle();
- if (pool.getPoolProperties().isTestWhileIdle())
- pool.testAllIdle();
- } catch (Exception x) {
- log.error("", x);
- } //catch
- } //end if
- } //while
- } //run
-
- public void stopRunning() {
- run = false;
- interrupt();
- }
- }
-}
+++ /dev/null
-/*
- * 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.util.Hashtable;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanRegistration;
-import javax.management.MBeanServer;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-
-
-/**
- * A DataSource that can be instantiated through IoC and implements the DataSource interface
- * since the DataSourceProxy is used as a generic proxy.
- * The DataSource simply wraps a {@link ConnectionPool} in order to provide a standard interface to the user.
- * @author Filip Hanik
- * @version 1.0
- */
-public class DataSource extends DataSourceProxy implements javax.sql.DataSource,MBeanRegistration, org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean {
- private static final Log log = LogFactory.getLog(DataSource.class);
-
- /**
- * Constructor for reflection only. A default set of pool properties will be created.
- */
- public DataSource() {
- super();
- }
-
- /**
- * Constructs a DataSource object wrapping a connection
- * @param poolProperties
- */
- public DataSource(PoolConfiguration poolProperties) {
- super(poolProperties);
- }
-
-//===============================================================================
-// JMX Operations - Register the actual pool itself under the tomcat.jdbc domain
-//===============================================================================
- protected volatile ObjectName oname = null;
-
- /**
- * Unregisters the underlying connection pool mbean.<br/>
- * {@inheritDoc}
- */
- public void postDeregister() {
- if (oname!=null) unregisterJmx();
- }
-
- /**
- * no-op<br/>
- * {@inheritDoc}
- */
- public void postRegister(Boolean registrationDone) {
- // NOOP
- }
-
-
- /**
- * no-op<br/>
- * {@inheritDoc}
- */
- public void preDeregister() throws Exception {
- // NOOP
- }
-
- /**
- * If the connection pool MBean exists, it will be registered during this operation.<br/>
- * {@inheritDoc}
- */
- public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
- try {
- this.oname = createObjectName(name);
- if (oname!=null) registerJmx();
- }catch (MalformedObjectNameException x) {
- log.error("Unable to create object name for JDBC pool.",x);
- }
- return name;
- }
-
- /**
- * Creates the ObjectName for the ConnectionPoolMBean object to be registered
- * @param original the ObjectName for the DataSource
- * @return the ObjectName for the ConnectionPoolMBean
- * @throws MalformedObjectNameException
- */
- public ObjectName createObjectName(ObjectName original) throws MalformedObjectNameException {
- String domain = "tomcat.jdbc";
- Hashtable<String,String> properties = original.getKeyPropertyList();
- String origDomain = original.getDomain();
- properties.put("type", "ConnectionPool");
- properties.put("class", this.getClass().getName());
- if (original.getKeyProperty("path")!=null) {
- properties.put("engine", origDomain);
- }
- ObjectName name = new ObjectName(domain,properties);
- return name;
- }
-
- /**
- * Registers the ConnectionPoolMBean under a unique name based on the ObjectName for the DataSource
- */
- protected void registerJmx() {
- try {
- if (pool.getJmxPool()!=null) {
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- mbs.registerMBean(pool.getJmxPool(), oname);
- }
- } catch (Exception e) {
- log.error("Unable to register JDBC pool with JMX",e);
- }
- }
-
- /**
- *
- */
- protected void unregisterJmx() {
- try {
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- mbs.unregisterMBean(oname);
- } catch (InstanceNotFoundException ignore) {
- // NOOP
- } catch (Exception e) {
- log.error("Unable to unregister JDBC pool with JMX",e);
- }
- }
-
-
-}
+++ /dev/null
-/*
- * 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.IOException;
-import java.sql.Connection;
-import java.util.Hashtable;
-import java.util.Properties;
-
-import javax.management.ObjectName;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.Name;
-import javax.naming.NamingException;
-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>
- * <li>fairQueue - true of false, whether the pool should sacrifice a little bit of performance for true fairness.</li>
- *</ol>
- * @author Craig R. McClanahan
- * @author Dirk Verbeeck
- * @author Filip Hanik
- */
-public class DataSourceFactory implements ObjectFactory {
- private static final 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_MAXAGE = "maxAge";
-
- 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_VALIDATOR_CLASS_NAME = "validatorClassName";
-
- 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_ABANDONWHENPERCENTAGEFULL = "abandonWhenPercentageFull";
-
- 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";
- protected final static String PROP_FAIR_QUEUE = "fairQueue";
-
- protected static final String PROP_USE_EQUALS = "useEquals";
- protected static final String PROP_USE_CON_LOCK = "useLock";
-
- protected static final String PROP_DATASOURCE= "dataSource";
- protected static final String PROP_DATASOURCE_JNDI = "dataSourceJNDI";
-
- protected static final String PROP_SUSPECT_TIMEOUT = "suspectTimeout";
-
- protected static final String PROP_ALTERNATE_USERNAME_ALLOWED = "alternateUsernameAllowed";
-
-
- public static final int UNKNOWN_TRANSACTIONISOLATION = -1;
-
- public static final String OBJECT_NAME = "object_name";
-
-
- 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,
- PROP_FAIR_QUEUE,
- PROP_USE_EQUALS,
- OBJECT_NAME,
- PROP_ABANDONWHENPERCENTAGEFULL,
- PROP_MAXAGE,
- PROP_USE_CON_LOCK,
- PROP_DATASOURCE,
- PROP_DATASOURCE_JNDI,
- PROP_ALTERNATE_USERNAME_ALLOWED
- };
-
- // -------------------------------------------------- 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;
- boolean XA = false;
- boolean ok = false;
- if ("javax.sql.DataSource".equals(ref.getClassName())) {
- ok = true;
- }
- if ("javax.sql.XADataSource".equals(ref.getClassName())) {
- ok = true;
- XA = true;
- }
- if (org.apache.tomcat.jdbc.pool.DataSource.class.getName().equals(ref.getClassName())) {
- ok = true;
- }
-
- if (!ok) {
- log.warn(ref.getClassName()+" is not a valid class name/type for this JNDI factory.");
- 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,nameCtx,XA);
- }
-
- public static PoolConfiguration parsePoolProperties(Properties properties) throws IOException{
- PoolConfiguration poolProperties = new PoolProperties();
- String value = null;
-
- value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT);
- if (value != null) {
- poolProperties.setDefaultAutoCommit(Boolean.valueOf(value));
- }
-
- value = properties.getProperty(PROP_DEFAULTREADONLY);
- if (value != null) {
- poolProperties.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;
- }
- }
- poolProperties.setDefaultTransactionIsolation(level);
- }
-
- value = properties.getProperty(PROP_DEFAULTCATALOG);
- if (value != null) {
- poolProperties.setDefaultCatalog(value);
- }
-
- value = properties.getProperty(PROP_DRIVERCLASSNAME);
- if (value != null) {
- poolProperties.setDriverClassName(value);
- }
-
- value = properties.getProperty(PROP_MAXACTIVE);
- if (value != null) {
- poolProperties.setMaxActive(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MAXIDLE);
- if (value != null) {
- poolProperties.setMaxIdle(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MINIDLE);
- if (value != null) {
- poolProperties.setMinIdle(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_INITIALSIZE);
- if (value != null) {
- poolProperties.setInitialSize(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MAXWAIT);
- if (value != null) {
- poolProperties.setMaxWait(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_TESTONBORROW);
- if (value != null) {
- poolProperties.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
- }
-
- value = properties.getProperty(PROP_TESTONRETURN);
- if (value != null) {
- poolProperties.setTestOnReturn(Boolean.valueOf(value).booleanValue());
- }
-
- value = properties.getProperty(PROP_TESTONCONNECT);
- if (value != null) {
- poolProperties.setTestOnConnect(Boolean.valueOf(value).booleanValue());
- }
-
- value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
- if (value != null) {
- poolProperties.setTimeBetweenEvictionRunsMillis(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN);
- if (value != null) {
- poolProperties.setNumTestsPerEvictionRun(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS);
- if (value != null) {
- poolProperties.setMinEvictableIdleTimeMillis(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_TESTWHILEIDLE);
- if (value != null) {
- poolProperties.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
- }
-
- value = properties.getProperty(PROP_PASSWORD);
- if (value != null) {
- poolProperties.setPassword(value);
- }
-
- value = properties.getProperty(PROP_URL);
- if (value != null) {
- poolProperties.setUrl(value);
- }
-
- value = properties.getProperty(PROP_USERNAME);
- if (value != null) {
- poolProperties.setUsername(value);
- }
-
- value = properties.getProperty(PROP_VALIDATIONQUERY);
- if (value != null) {
- poolProperties.setValidationQuery(value);
- }
-
- value = properties.getProperty(PROP_VALIDATOR_CLASS_NAME);
- if (value != null) {
- poolProperties.setValidatorClassName(value);
- }
-
- value = properties.getProperty(PROP_VALIDATIONINTERVAL);
- if (value != null) {
- poolProperties.setValidationInterval(Long.parseLong(value));
- }
-
- value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
- if (value != null) {
- poolProperties.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
- }
-
- value = properties.getProperty(PROP_REMOVEABANDONED);
- if (value != null) {
- poolProperties.setRemoveAbandoned(Boolean.valueOf(value).booleanValue());
- }
-
- value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
- if (value != null) {
- poolProperties.setRemoveAbandonedTimeout(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_LOGABANDONED);
- if (value != null) {
- poolProperties.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);
- poolProperties.setDbProperties(p);
- } else {
- poolProperties.setDbProperties(new Properties());
- }
-
- if (poolProperties.getUsername()!=null) {
- poolProperties.getDbProperties().setProperty("user",poolProperties.getUsername());
- }
- if (poolProperties.getPassword()!=null) {
- poolProperties.getDbProperties().setProperty("password",poolProperties.getPassword());
- }
-
- value = properties.getProperty(PROP_INITSQL);
- if (value != null) {
- poolProperties.setInitSQL(value);
- }
-
- value = properties.getProperty(PROP_INTERCEPTORS);
- if (value != null) {
- poolProperties.setJdbcInterceptors(value);
- }
-
- value = properties.getProperty(PROP_JMX_ENABLED);
- if (value != null) {
- poolProperties.setJmxEnabled(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_FAIR_QUEUE);
- if (value != null) {
- poolProperties.setFairQueue(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_USE_EQUALS);
- if (value != null) {
- poolProperties.setUseEquals(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(OBJECT_NAME);
- if (value != null) {
- poolProperties.setName(ObjectName.quote(value));
- }
-
- value = properties.getProperty(PROP_ABANDONWHENPERCENTAGEFULL);
- if (value != null) {
- poolProperties.setAbandonWhenPercentageFull(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MAXAGE);
- if (value != null) {
- poolProperties.setMaxAge(Long.parseLong(value));
- }
-
- value = properties.getProperty(PROP_USE_CON_LOCK);
- if (value != null) {
- poolProperties.setUseLock(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_DATASOURCE);
- if (value != null) {
- //this should never happen
- throw new IllegalArgumentException("Can't set dataSource property as a string, this must be a javax.sql.DataSource object.");
-
- }
-
- value = properties.getProperty(PROP_DATASOURCE_JNDI);
- if (value != null) {
- poolProperties.setDataSourceJNDI(value);
- }
-
- value = properties.getProperty(PROP_SUSPECT_TIMEOUT);
- if (value != null) {
- poolProperties.setSuspectTimeout(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_ALTERNATE_USERNAME_ALLOWED);
- if (value != null) {
- poolProperties.setAlternateUsernameAllowed(Boolean.parseBoolean(value));
- }
-
- return poolProperties;
- }
-
- /**
- * Creates and configures a {@link DataSource} instance based on the
- * given properties.
- *
- * @param properties the datasource configuration properties
- * @throws Exception if an error occurs creating the data source
- */
- public DataSource createDataSource(Properties properties) throws Exception {
- return createDataSource(properties,null,false);
- }
- public DataSource createDataSource(Properties properties,Context context, boolean XA) throws Exception {
- PoolConfiguration poolProperties = DataSourceFactory.parsePoolProperties(properties);
- if (poolProperties.getDataSourceJNDI()!=null && poolProperties.getDataSource()==null) {
- performJNDILookup(context, poolProperties);
- }
- org.apache.tomcat.jdbc.pool.DataSource dataSource = XA?
- new org.apache.tomcat.jdbc.pool.XADataSource(poolProperties) :
- new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
- //initialise the pool itself
- dataSource.createPool();
- // Return the configured DataSource instance
- return dataSource;
- }
-
- public void performJNDILookup(Context context, PoolConfiguration poolProperties) {
- Object jndiDS = null;
- try {
- if (context!=null) {
- jndiDS = context.lookup(poolProperties.getDataSourceJNDI());
- } else {
- log.warn("dataSourceJNDI property is configued, but local JNDI context is null.");
- }
- } catch (NamingException e) {
- log.debug("The name \""+poolProperties.getDataSourceJNDI()+"\" can not be found in the local context.");
- }
- if (jndiDS==null) {
- try {
- context = (Context) (new InitialContext());
- jndiDS = context.lookup(poolProperties.getDataSourceJNDI());
- } catch (NamingException e) {
- log.warn("The name \""+poolProperties.getDataSourceJNDI()+"\" can not be found in the InitialContext.");
- }
- }
- if (jndiDS!=null) {
- poolProperties.setDataSource(jndiDS);
- }
- }
-
- /**
- * <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 IOException {
- return PoolProperties.getProperties(propText,null);
- }
-
-}
+++ /dev/null
-/*
- * 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 java.util.Properties;
-import java.util.concurrent.Future;
-
-import javax.sql.XAConnection;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
-
-/**
- *
- * The DataSource proxy lets us implements methods that don't exist in the current
- * compiler JDK but might be methods that are part of a future JDK DataSource interface.
- * <br/>
- * It's a trick to work around compiler issues when implementing interfaces. For example,
- * I could put in Java 6 methods of javax.sql.DataSource here, and compile it with JDK 1.5
- * and still be able to run under Java 6 without getting NoSuchMethodException.
- *
- * @author Filip Hanik
- * @version 1.0
- */
-
-public class DataSourceProxy implements PoolConfiguration {
- private static final Log log = LogFactory.getLog(DataSourceProxy.class);
-
- protected volatile ConnectionPool pool = null;
-
- protected PoolConfiguration poolProperties = null;
-
- public DataSourceProxy() {
- this(new PoolProperties());
- }
-
- public DataSourceProxy(PoolConfiguration poolProperties) {
- if (poolProperties == null) throw new NullPointerException("PoolConfiguration can not be null.");
- this.poolProperties = poolProperties;
- }
-
-
- 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;
- }
-
- /**
- * {@link javax.sql.DataSource#getConnection()}
- */
- public Connection getConnection(String username, String password) throws SQLException {
- if (this.getPoolProperties().isAlternateUsernameAllowed()) {
- if (pool == null)
- return createPool().getConnection(username,password);
- return pool.getConnection(username,password);
- } else {
- return getConnection();
- }
- }
-
- public PoolConfiguration getPoolProperties() {
- return poolProperties;
- }
-
- /**
- * Sets up the connection pool, by creating a pooling driver.
- * @return Driver
- * @throws SQLException
- */
- public synchronized ConnectionPool createPool() throws SQLException {
- if (pool != null) {
- return pool;
- } else {
- pool = new ConnectionPool(poolProperties);
- return pool;
- }
- }
-
- /**
- * {@link javax.sql.DataSource#getConnection()}
- */
-
- public Connection getConnection() throws SQLException {
- if (pool == null)
- return createPool().getConnection();
- return pool.getConnection();
- }
-
- /**
- * Invokes an sync operation to retrieve the connection.
- * @return a Future containing a reference to the connection when it becomes available
- * @throws SQLException
- */
- public Future<Connection> getConnectionAsync() throws SQLException {
- if (pool == null)
- return createPool().getConnectionAsync();
- return pool.getConnectionAsync();
- }
-
- /**
- * {@link javax.sql.XADataSource#getXAConnection()}
- */
- public XAConnection getXAConnection() throws SQLException {
- Connection con = getConnection();
- if (con instanceof XAConnection) {
- return (XAConnection)con;
- } else {
- try {con.close();} catch (Exception ignore){}
- throw new SQLException("Connection from pool does not implement javax.sql.XAConnection");
- }
- }
-
- /**
- * {@link javax.sql.XADataSource#getXAConnection(String, String)}
- */
- public XAConnection getXAConnection(String username, String password) throws SQLException {
- Connection con = getConnection(username, password);
- if (con instanceof XAConnection) {
- return (XAConnection)con;
- } else {
- try {con.close();} catch (Exception ignore){}
- throw new SQLException("Connection from pool does not implement javax.sql.XAConnection");
- }
- }
-
-
- /**
- * {@link javax.sql.DataSource#getConnection()}
- */
- public PooledConnection getPooledConnection() throws SQLException {
- return (PooledConnection) getConnection();
- }
-
- /**
- * {@link javax.sql.DataSource#getConnection()}
- */
- public PooledConnection getPooledConnection(String username,
- String password) throws SQLException {
- return (PooledConnection) getConnection();
- }
-
- public ConnectionPool getPool() {
- return pool;
- }
-
-
- public void close() {
- close(false);
- }
- public void close(boolean all) {
- try {
- if (pool != null) {
- final ConnectionPool p = pool;
- pool = null;
- if (p!=null) {
- p.close(all);
- }
- }
- }catch (Exception x) {
- log.warn("Error duing connection pool closure.", x);
- }
- }
-
- public int getPoolSize() throws SQLException{
- final ConnectionPool p = pool;
- if (p == null) return 0;
- else return p.getSize();
- }
-
-
- public String toString() {
- return super.toString()+"{"+getPoolProperties()+"}";
- }
-
-
-/*-----------------------------------------------------------------------*/
-// PROPERTIES WHEN NOT USED WITH FACTORY
-/*------------------------------------------------------------------------*/
-
- /**
- * {@inheritDoc}
- */
-
- public String getPoolName() {
- return pool.getName();
- }
-
-
- public void setPoolProperties(PoolConfiguration poolProperties) {
- this.poolProperties = poolProperties;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDriverClassName(String driverClassName) {
- this.poolProperties.setDriverClassName(driverClassName);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setInitialSize(int initialSize) {
- this.poolProperties.setInitialSize(initialSize);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setInitSQL(String initSQL) {
- this.poolProperties.setInitSQL(initSQL);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setLogAbandoned(boolean logAbandoned) {
- this.poolProperties.setLogAbandoned(logAbandoned);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMaxActive(int maxActive) {
- this.poolProperties.setMaxActive(maxActive);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMaxIdle(int maxIdle) {
- this.poolProperties.setMaxIdle(maxIdle);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMaxWait(int maxWait) {
- this.poolProperties.setMaxWait(maxWait);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
- this.poolProperties.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMinIdle(int minIdle) {
- this.poolProperties.setMinIdle(minIdle);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
- this.poolProperties.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setPassword(String password) {
- this.poolProperties.setPassword(password);
- this.poolProperties.getDbProperties().setProperty("password",this.poolProperties.getPassword());
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setRemoveAbandoned(boolean removeAbandoned) {
- this.poolProperties.setRemoveAbandoned(removeAbandoned);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
- this.poolProperties.setRemoveAbandonedTimeout(removeAbandonedTimeout);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTestOnBorrow(boolean testOnBorrow) {
- this.poolProperties.setTestOnBorrow(testOnBorrow);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTestOnConnect(boolean testOnConnect) {
- this.poolProperties.setTestOnConnect(testOnConnect);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTestOnReturn(boolean testOnReturn) {
- this.poolProperties.setTestOnReturn(testOnReturn);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTestWhileIdle(boolean testWhileIdle) {
- this.poolProperties.setTestWhileIdle(testWhileIdle);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
- this.poolProperties.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setUrl(String url) {
- this.poolProperties.setUrl(url);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setUsername(String username) {
- this.poolProperties.setUsername(username);
- this.poolProperties.getDbProperties().setProperty("user",getPoolProperties().getUsername());
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setValidationInterval(long validationInterval) {
- this.poolProperties.setValidationInterval(validationInterval);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setValidationQuery(String validationQuery) {
- this.poolProperties.setValidationQuery(validationQuery);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setValidatorClassName(String className) {
- this.poolProperties.setValidatorClassName(className);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setJdbcInterceptors(String interceptors) {
- this.getPoolProperties().setJdbcInterceptors(interceptors);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setJmxEnabled(boolean enabled) {
- this.getPoolProperties().setJmxEnabled(enabled);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setFairQueue(boolean fairQueue) {
- this.getPoolProperties().setFairQueue(fairQueue);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setUseLock(boolean useLock) {
- this.getPoolProperties().setUseLock(useLock);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDefaultCatalog(String catalog) {
- this.getPoolProperties().setDefaultCatalog(catalog);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDefaultAutoCommit(Boolean autocommit) {
- this.getPoolProperties().setDefaultAutoCommit(autocommit);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
- this.getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
- }
-
- /**
- * {@inheritDoc}
- */
-
- 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);
- }
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setUseEquals(boolean useEquals) {
- this.getPoolProperties().setUseEquals(useEquals);
- }
-
- /**
- * no-op
- * {@link javax.sql.DataSource#getLogWriter}
- */
- public PrintWriter getLogWriter() throws SQLException {
- return null;
- }
-
-
- /**
- * no-op
- * {@link javax.sql.DataSource#setLogWriter(PrintWriter)}
- */
- public void setLogWriter(PrintWriter out) throws SQLException {
- // NOOP
- }
-
- /**
- * no-op
- * {@link javax.sql.DataSource#getLoginTimeout}
- */
- public int getLoginTimeout() {
- if (poolProperties == null) {
- return 0;
- } else {
- return poolProperties.getMaxWait() / 1000;
- }
- }
-
- /**
- * {@link javax.sql.DataSource#setLoginTimeout(int)}
- */
- public void setLoginTimeout(int i) {
- if (poolProperties == null) {
- return;
- } else {
- poolProperties.setMaxWait(1000 * i);
- }
-
- }
-
-
- /**
- * {@inheritDoc}
- */
-
- public int getSuspectTimeout() {
- return getPoolProperties().getSuspectTimeout();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setSuspectTimeout(int seconds) {
- getPoolProperties().setSuspectTimeout(seconds);
- }
-
- //===============================================================================
-// Expose JMX attributes through Tomcat's dynamic reflection
-//===============================================================================
- /**
- * If the pool has not been created, it will be created during this call.
- * @return the number of established but idle connections
- */
- public int getIdle() {
- try {
- return createPool().getIdle();
- }catch (SQLException x) {
- throw new RuntimeException(x);
- }
- }
-
- /**
- * {@link #getIdle()}
- */
- public int getNumIdle() {
- return getIdle();
- }
-
- /**
- * Forces an abandon check on the connection pool.
- * If connections that have been abandoned exists, they will be closed during this run
- */
- public void checkAbandoned() {
- try {
- createPool().checkAbandoned();
- }catch (SQLException x) {
- throw new RuntimeException(x);
- }
- }
-
- /**
- * Forces a check for resizing of the idle connections
- */
- public void checkIdle() {
- try {
- createPool().checkIdle();
- }catch (SQLException x) {
- throw new RuntimeException(x);
- }
- }
-
- /**
- * @return number of connections in use by the application
- */
- public int getActive() {
- try {
- return createPool().getActive();
- }catch (SQLException x) {
- throw new RuntimeException(x);
- }
- }
-
- /**
- * @return number of connections in use by the application
- * {@link DataSource#getActive()}
- */
- public int getNumActive() {
- return getActive();
- }
-
- /**
- * @return number of threads waiting for a connection
- */
- public int getWaitCount() {
- try {
- return createPool().getWaitCount();
- }catch (SQLException x) {
- throw new RuntimeException(x);
- }
- }
-
- /**
- * @return the current size of the pool
- */
- public int getSize() {
- try {
- return createPool().getSize();
- }catch (SQLException x) {
- throw new RuntimeException(x);
- }
- }
-
- /**
- * Performs a validation on idle connections
- */
- public void testIdle() {
- try {
- createPool().testAllIdle();
- }catch (SQLException x) {
- throw new RuntimeException(x);
- }
- }
- //=========================================================
- // PROPERTIES / CONFIGURATION
- //=========================================================
-
- /**
- * {@inheritDoc}
- */
-
- public String getConnectionProperties() {
- return getPoolProperties().getConnectionProperties();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Properties getDbProperties() {
- return getPoolProperties().getDbProperties();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getDefaultCatalog() {
- return getPoolProperties().getDefaultCatalog();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getDefaultTransactionIsolation() {
- return getPoolProperties().getDefaultTransactionIsolation();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getDriverClassName() {
- return getPoolProperties().getDriverClassName();
- }
-
-
- /**
- * {@inheritDoc}
- */
-
- public int getInitialSize() {
- return getPoolProperties().getInitialSize();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getInitSQL() {
- return getPoolProperties().getInitSQL();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getJdbcInterceptors() {
- return getPoolProperties().getJdbcInterceptors();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMaxActive() {
- return getPoolProperties().getMaxActive();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMaxIdle() {
- return getPoolProperties().getMaxIdle();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMaxWait() {
- return getPoolProperties().getMaxWait();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMinEvictableIdleTimeMillis() {
- return getPoolProperties().getMinEvictableIdleTimeMillis();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMinIdle() {
- return getPoolProperties().getMinIdle();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public long getMaxAge() {
- return getPoolProperties().getMaxAge();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getName() {
- return getPoolProperties().getName();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getNumTestsPerEvictionRun() {
- return getPoolProperties().getNumTestsPerEvictionRun();
- }
-
- /**
- * @return DOES NOT RETURN THE PASSWORD, IT WOULD SHOW UP IN JMX
- */
- public String getPassword() {
- return "Password not available as DataSource/JMX operation.";
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getRemoveAbandonedTimeout() {
- return getPoolProperties().getRemoveAbandonedTimeout();
- }
-
-
- /**
- * {@inheritDoc}
- */
-
- public int getTimeBetweenEvictionRunsMillis() {
- return getPoolProperties().getTimeBetweenEvictionRunsMillis();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getUrl() {
- return getPoolProperties().getUrl();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getUsername() {
- return getPoolProperties().getUsername();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public long getValidationInterval() {
- return getPoolProperties().getValidationInterval();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getValidationQuery() {
- return getPoolProperties().getValidationQuery();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getValidatorClassName() {
- return getPoolProperties().getValidatorClassName();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Validator getValidator() {
- return getPoolProperties().getValidator();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isAccessToUnderlyingConnectionAllowed() {
- return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Boolean isDefaultAutoCommit() {
- return getPoolProperties().isDefaultAutoCommit();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Boolean isDefaultReadOnly() {
- return getPoolProperties().isDefaultReadOnly();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isLogAbandoned() {
- return getPoolProperties().isLogAbandoned();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isPoolSweeperEnabled() {
- return getPoolProperties().isPoolSweeperEnabled();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isRemoveAbandoned() {
- return getPoolProperties().isRemoveAbandoned();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getAbandonWhenPercentageFull() {
- return getPoolProperties().getAbandonWhenPercentageFull();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isTestOnBorrow() {
- return getPoolProperties().isTestOnBorrow();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isTestOnConnect() {
- return getPoolProperties().isTestOnConnect();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isTestOnReturn() {
- return getPoolProperties().isTestOnReturn();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isTestWhileIdle() {
- return getPoolProperties().isTestWhileIdle();
- }
-
-
- /**
- * {@inheritDoc}
- */
-
- public Boolean getDefaultAutoCommit() {
- return getPoolProperties().getDefaultAutoCommit();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Boolean getDefaultReadOnly() {
- return getPoolProperties().getDefaultReadOnly();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
- return getPoolProperties().getJdbcInterceptorsAsArray();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean getUseLock() {
- return getPoolProperties().getUseLock();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isFairQueue() {
- return getPoolProperties().isFairQueue();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isJmxEnabled() {
- return getPoolProperties().isJmxEnabled();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isUseEquals() {
- return getPoolProperties().isUseEquals();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setAbandonWhenPercentageFull(int percentage) {
- getPoolProperties().setAbandonWhenPercentageFull(percentage);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
- getPoolProperties().setAccessToUnderlyingConnectionAllowed(accessToUnderlyingConnectionAllowed);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDbProperties(Properties dbProperties) {
- getPoolProperties().setDbProperties(dbProperties);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDefaultReadOnly(Boolean defaultReadOnly) {
- getPoolProperties().setDefaultReadOnly(defaultReadOnly);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMaxAge(long maxAge) {
- getPoolProperties().setMaxAge(maxAge);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setName(String name) {
- getPoolProperties().setName(name);
- }
-
- /**
- * {@inheritDoc}
- */
- public void setDataSource(Object ds) {
- getPoolProperties().setDataSource(ds);
- }
-
- /**
- * {@inheritDoc}
- */
- public Object getDataSource() {
- return getPoolProperties().getDataSource();
- }
-
-
- /**
- * {@inheritDoc}
- */
- public void setDataSourceJNDI(String jndiDS) {
- getPoolProperties().setDataSourceJNDI(jndiDS);
- }
-
- /**
- * {@inheritDoc}
- */
- public String getDataSourceJNDI() {
- return getPoolProperties().getDataSourceJNDI();
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isAlternateUsernameAllowed() {
- return getPoolProperties().isAlternateUsernameAllowed();
- }
-
- /**
- * {@inheritDoc}
- */
- public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
- getPoolProperties().setAlternateUsernameAllowed(alternateUsernameAllowed);
- }
-
-}
+++ /dev/null
-/*
- * 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.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- *
- * A simple implementation of a blocking queue with fairness waiting.
- * invocations to method poll(...) will get handed out in the order they were received.
- * Locking is fine grained, a shared lock is only used during the first level of contention, waiting is done in a
- * lock per thread basis so that order is guaranteed once the thread goes into a suspended monitor state.
- * <br/>
- * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented.
- * @author Filip Hanik
- *
- */
-
-public class FairBlockingQueue<E> implements BlockingQueue<E> {
-
- /**
- * This little sucker is used to reorder the way to do
- * {@link java.util.concurrent.locks.Lock#lock()},
- * {@link java.util.concurrent.locks.Lock#unlock()}
- * and
- * {@link java.util.concurrent.CountDownLatch#countDown()}
- * during the {@link #poll(long, TimeUnit)} operation.
- * On Linux, it performs much better if we count down while we hold the global
- * lock, on Solaris its the other way around.
- * Until we have tested other platforms we only check for Linux.
- */
- final static boolean isLinux = "Linux".equals(System.getProperty("os.name")) &&
- (!Boolean.getBoolean(FairBlockingQueue.class.getName()+".ignoreOS"));
-
- /**
- * Phase one entry lock in order to give out
- * per-thread-locks for the waiting phase we have
- * a phase one lock during the contention period.
- */
- final ReentrantLock lock = new ReentrantLock(false);
-
- /**
- * All the objects in the pool are stored in a simple linked list
- */
- final LinkedList<E> items;
-
- /**
- * All threads waiting for an object are stored in a linked list
- */
- final LinkedList<ExchangeCountDownLatch<E>> waiters;
-
- /**
- * Creates a new fair blocking queue.
- */
- public FairBlockingQueue() {
- items = new LinkedList<E>();
- waiters = new LinkedList<ExchangeCountDownLatch<E>>();
- }
-
- //------------------------------------------------------------------
- // USED BY CONPOOL IMPLEMENTATION
- //------------------------------------------------------------------
- /**
- * Will always return true, queue is unbounded.
- * {@inheritDoc}
- */
- public boolean offer(E e) {
- //during the offer, we will grab the main lock
- final ReentrantLock lock = this.lock;
- lock.lock();
- ExchangeCountDownLatch<E> c = null;
- try {
- //check to see if threads are waiting for an object
- if (waiters.size() > 0) {
- //if threads are waiting grab the latch for that thread
- c = waiters.poll();
- //give the object to the thread instead of adding it to the pool
- c.setItem(e);
- if (isLinux) c.countDown();
- } else {
- //we always add first, so that the most recently used object will be given out
- items.addFirst(e);
- }
- } finally {
- lock.unlock();
- }
- //if we exchanged an object with another thread, wake it up.
- if (!isLinux && c!=null) c.countDown();
- //we have an unbounded queue, so always return true
- return true;
- }
-
- /**
- * Will never timeout, as it invokes the {@link #offer(Object)} method.
- * Once a lock has been acquired, the
- * {@inheritDoc}
- */
- public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
- return offer(e);
- }
-
- /**
- * Fair retrieval of an object in the queue.
- * Objects are returned in the order the threads requested them.
- * {@inheritDoc}
- */
- public E poll(long timeout, TimeUnit unit) throws InterruptedException {
- E result = null;
- final ReentrantLock lock = this.lock;
- boolean error = true;
- //acquire the global lock until we know what to do
- lock.lock();
- try {
- //check to see if we have objects
- result = items.poll();
- if (result==null && timeout>0) {
- //the queue is empty we will wait for an object
- ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<E>(1);
- //add to the bottom of the wait list
- waiters.addLast(c);
- //unlock the global lock
- lock.unlock();
- //wait for the specified timeout
- if (!c.await(timeout, unit)) {
- //if we timed out, remove ourselves from the waitlist
- lock.lock();
- waiters.remove(c);
- lock.unlock();
- }
- //return the item we received, can be null if we timed out
- result = c.getItem();
- } else {
- //we have an object, release
- lock.unlock();
- }
- error = false;
- } finally {
- if (error && lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- return result;
- }
-
- /**
- * Request an item from the queue asynchronously
- * @return - a future pending the result from the queue poll request
- */
- public Future<E> pollAsync() {
- Future<E> result = null;
- final ReentrantLock lock = this.lock;
- boolean error = true;
- //grab the global lock
- lock.lock();
- try {
- //check to see if we have objects in the queue
- E item = items.poll();
- if (item==null) {
- //queue is empty, add ourselves as waiters
- ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<E>(1);
- waiters.addLast(c);
- lock.unlock();
- //return a future that will wait for the object
- result = new ItemFuture<E>(c);
- } else {
- lock.unlock();
- //return a future with the item
- result = new ItemFuture<E>(item);
- }
- error = false;
- } finally {
- if (error && lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean remove(Object e) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- return items.remove(e);
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public int size() {
- return items.size();
- }
-
- /**
- * {@inheritDoc}
- */
- public Iterator<E> iterator() {
- return new FairIterator();
- }
-
- /**
- * {@inheritDoc}
- */
- public E poll() {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- return items.poll();
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean contains(Object e) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- return items.contains(e);
- } finally {
- lock.unlock();
- }
- }
-
-
- //------------------------------------------------------------------
- // NOT USED BY CONPOOL IMPLEMENTATION
- //------------------------------------------------------------------
- /**
- * {@inheritDoc}
- */
- public boolean add(E e) {
- return offer(e);
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public int drainTo(Collection<? super E> c, int maxElements) {
- throw new UnsupportedOperationException("int drainTo(Collection<? super E> c, int maxElements)");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
-
- public int drainTo(Collection<? super E> c) {
- return drainTo(c,Integer.MAX_VALUE);
- }
-
- /**
- * {@inheritDoc}
- */
- public void put(E e) throws InterruptedException {
- offer(e);
- }
-
- /**
- * {@inheritDoc}
- */
- public int remainingCapacity() {
- return Integer.MAX_VALUE - size();
- }
-
- /**
- * {@inheritDoc}
- */
- public E take() throws InterruptedException {
- return this.poll(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean addAll(Collection<? extends E> c) {
- Iterator<? extends E> i = c.iterator();
- while (i.hasNext()) {
- E e = i.next();
- offer(e);
- }
- return true;
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public void clear() {
- throw new UnsupportedOperationException("void clear()");
-
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public boolean containsAll(Collection<?> c) {
- throw new UnsupportedOperationException("boolean containsAll(Collection<?> c)");
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isEmpty() {
- return size() == 0;
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public boolean removeAll(Collection<?> c) {
- throw new UnsupportedOperationException("boolean removeAll(Collection<?> c)");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public boolean retainAll(Collection<?> c) {
- throw new UnsupportedOperationException("boolean retainAll(Collection<?> c)");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public Object[] toArray() {
- throw new UnsupportedOperationException("Object[] toArray()");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public <T> T[] toArray(T[] a) {
- throw new UnsupportedOperationException("<T> T[] toArray(T[] a)");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public E element() {
- throw new UnsupportedOperationException("E element()");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public E peek() {
- throw new UnsupportedOperationException("E peek()");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public E remove() {
- throw new UnsupportedOperationException("E remove()");
- }
-
-
-
- //------------------------------------------------------------------
- // Non cancellable Future used to check and see if a connection has been made available
- //------------------------------------------------------------------
- protected class ItemFuture<T> implements Future<T> {
- protected volatile T item = null;
- protected volatile ExchangeCountDownLatch<T> latch = null;
- protected volatile boolean canceled = false;
-
- public ItemFuture(T item) {
- this.item = item;
- }
-
- public ItemFuture(ExchangeCountDownLatch<T> latch) {
- this.latch = latch;
- }
-
- public boolean cancel(boolean mayInterruptIfRunning) {
- return false; //don't allow cancel for now
- }
-
- public T get() throws InterruptedException, ExecutionException {
- if (item!=null) {
- return item;
- } else if (latch!=null) {
- latch.await();
- return latch.getItem();
- } else {
- throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
- }
- }
-
- public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- if (item!=null) {
- return item;
- } else if (latch!=null) {
- boolean timedout = !latch.await(timeout, unit);
- if (timedout) throw new TimeoutException();
- else return latch.getItem();
- } else {
- throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
- }
- }
-
- public boolean isCancelled() {
- return false;
- }
-
- public boolean isDone() {
- return (item!=null || latch.getItem()!=null);
- }
-
- }
-
- //------------------------------------------------------------------
- // Count down latch that can be used to exchange information
- //------------------------------------------------------------------
- protected class ExchangeCountDownLatch<T> extends CountDownLatch {
- protected volatile T item;
- public ExchangeCountDownLatch(int i) {
- super(i);
- }
- public T getItem() {
- return item;
- }
- public void setItem(T item) {
- this.item = item;
- }
- }
-
- //------------------------------------------------------------------
- // Iterator safe from concurrent modification exceptions
- //------------------------------------------------------------------
- protected class FairIterator implements Iterator<E> {
- E[] elements = null;
- int index;
- E element = null;
-
- public FairIterator() {
- final ReentrantLock lock = FairBlockingQueue.this.lock;
- lock.lock();
- try {
- elements = (E[]) new Object[FairBlockingQueue.this.items.size()];
- FairBlockingQueue.this.items.toArray(elements);
- index = 0;
- } finally {
- lock.unlock();
- }
- }
- public boolean hasNext() {
- return index<elements.length;
- }
-
- public E next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- element = elements[index++];
- return element;
- }
-
- public void remove() {
- final ReentrantLock lock = FairBlockingQueue.this.lock;
- lock.lock();
- try {
- if (element!=null) {
- FairBlockingQueue.this.items.remove(element);
- }
- } finally {
- lock.unlock();
- }
- }
-
- }
-}
+++ /dev/null
-/*
- * 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;
-import java.util.Map;
-
-import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
-
-/**
- * Abstract class that is to be extended for implementations of interceptors.
- * Everytime an operation is called on the {@link java.sql.Connection} object the
- * {@link #invoke(Object, Method, Object[])} method on the interceptor will be called.
- * Interceptors are useful to change or improve behavior of the connection pool.<br/>
- * Interceptors can receive a set of properties. Each sub class is responsible for parsing the properties during runtime when they
- * are needed or simply override the {@link #setProperties(Map)} method.
- * Properties arrive in a key-value pair of Strings as they were received through the configuration.
- * This method is called once per cached connection object when the object is first configured.
- *
- * @author Filip Hanik
- * @version 1.0
- */
-public abstract class JdbcInterceptor implements InvocationHandler {
- /**
- * {@link java.sql.Connection#close()} method name
- */
- public static final String CLOSE_VAL = "close";
- /**
- * {@link Object#toString()} method name
- */
- public static final String TOSTRING_VAL = "toString";
- /**
- * {@link java.sql.Connection#isClosed()} method name
- */
- public static final String ISCLOSED_VAL = "isClosed";
- /**
- * {@link javax.sql.PooledConnection#getConnection()} method name
- */
- public static final String GETCONNECTION_VAL = "getConnection";
- /**
- * {@link java.sql.Wrapper#unwrap(Class)} method name
- */
- public static final String UNWRAP_VAL = "unwrap";
- /**
- * {@link java.sql.Wrapper#isWrapperFor(Class)} method name
- */
- public static final String ISWRAPPERFOR_VAL = "isWrapperFor";
-
-
- /**
- * Properties for this interceptor.
- */
- protected Map<String,InterceptorProperty> properties = null;
-
- /**
- * The next interceptor in the chain
- */
- private JdbcInterceptor next = null;
- /**
- * Property that decides how we do string comparison, default is to use
- * {@link String#equals(Object)}. If set to <code>false</code> then the
- * equality operator (==) is used.
- */
- private boolean useEquals = true;
-
- /**
- * Public constructor for instantation through reflection
- */
- public JdbcInterceptor() {
- // NOOP
- }
-
- /**
- * Gets invoked each time an operation on {@link java.sql.Connection} is invoked.
- * {@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();
- }
-
- /**
- * Returns the next interceptor in the chain
- * @return the next interceptor in the chain
- */
- public JdbcInterceptor getNext() {
- return next;
- }
-
- /**
- * configures the next interceptor in the chain
- * @param next
- */
- public void setNext(JdbcInterceptor next) {
- this.next = next;
- }
-
- /**
- * Performs a string comparison, using references unless the useEquals property is set to true.
- * @param name1
- * @param name2
- * @return true if name1 is equal to name2 based on {@link #useEquals}
- */
- public boolean compare(String name1, String name2) {
- if (isUseEquals()) {
- return name1.equals(name2);
- } else {
- return name1==name2;
- }
- }
-
- /**
- * Compares a method name (String) to a method (Method)
- * {@link #compare(String,String)}
- * Uses reference comparison unless the useEquals property is set to true
- * @param methodName
- * @param method
- * @return true if the name matches
- */
- public boolean compare(String methodName, Method method) {
- return compare(methodName, method.getName());
- }
-
- /**
- * Gets called each time the connection is borrowed from the pool
- * This means that if an interceptor holds a reference to the connection
- * the interceptor can be reused for another connection.
- * <br/>
- * This method may be called with null as both arguments when we are closing down the connection.
- * @param parent - the connection pool owning the connection
- * @param con - the pooled connection
- */
- public abstract void reset(ConnectionPool parent, PooledConnection con);
-
- /**
- * Called when {@link java.sql.Connection#close()} is called on the underlying connection.
- * This is to notify the interceptors, that the physical connection has been released.
- * Implementation of this method should be thought through with care, as no actions should trigger an exception.
- * @param parent - the connection pool that this connection belongs to
- * @param con - the pooled connection that holds this connection
- * @param finalizing - if this connection is finalizing. True means that the pooled connection will not reconnect the underlying connection
- */
- public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {
- }
-
-
- /**
- * Returns the properties configured for this interceptor
- * @return the configured properties for this interceptor
- */
- public Map<String,InterceptorProperty> getProperties() {
- return properties;
- }
-
- /**
- * Called during the creation of an interceptor
- * The properties can be set during the configuration of an interceptor
- * Override this method to perform type casts between string values and object properties
- * @param properties
- */
- public void setProperties(Map<String,InterceptorProperty> properties) {
- this.properties = properties;
- final String useEquals = "useEquals";
- InterceptorProperty p = properties.get(useEquals);
- if (p!=null) {
- setUseEquals(Boolean.parseBoolean(p.getValue()));
- }
- }
-
- /**
- * @return true if the compare method uses the Object.equals(Object) method
- * false if comparison is done on a reference level
- */
- public boolean isUseEquals() {
- return useEquals;
- }
-
- /**
- * Set to true if string comparisons (for the {@link #compare(String, Method)} and {@link #compare(String, String)} methods) should use the Object.equals(Object) method
- * The default is false
- * @param useEquals
- */
- public void setUseEquals(boolean useEquals) {
- this.useEquals = useEquals;
- }
-
- /**
- * This method is invoked by a connection pool when the pool is closed.
- * Interceptor classes can override this method if they keep static
- * variables or other tracking means around.
- * <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>
- * @param pool - the pool that is being closed.
- */
- public void poolClosed(ConnectionPool pool) {
- // NOOP
- }
-
- /**
- * This method is invoked by a connection pool when the pool is first started up, usually when the first connection is requested.
- * Interceptor classes can override this method if they keep static
- * variables or other tracking means around.
- * <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>
- * @param pool - the pool that is being closed.
- */
- public void poolStarted(ConnectionPool pool) {
- // NOOP
- }
-
-}
+++ /dev/null
-/*
- * 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.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * <b>EXPERIMENTAL AND NOT YET COMPLETE!</b>
- *
- *
- * An implementation of a blocking queue with fairness waiting and lock dispersal to avoid contention.
- * invocations to method poll(...) will get handed out in the order they were received.
- * Locking is fine grained, a shared lock is only used during the first level of contention, waiting is done in a
- * lock per thread basis so that order is guaranteed once the thread goes into a suspended monitor state.
- * <br/>
- * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented.
- * @author Filip Hanik
- *
- */
-
-public class MultiLockFairBlockingQueue<E> implements BlockingQueue<E> {
-
- final int LOCK_COUNT = Runtime.getRuntime().availableProcessors();
-
- final AtomicInteger putQueue = new AtomicInteger(0);
- final AtomicInteger pollQueue = new AtomicInteger(0);
-
- public int getNextPut() {
- int idx = Math.abs(putQueue.incrementAndGet()) % LOCK_COUNT;
- return idx;
- }
-
- public int getNextPoll() {
- int idx = Math.abs(pollQueue.incrementAndGet()) % LOCK_COUNT;
- return idx;
- }
- /**
- * Phase one entry lock in order to give out
- * per-thread-locks for the waiting phase we have
- * a phase one lock during the contention period.
- */
- private final ReentrantLock[] locks = new ReentrantLock[LOCK_COUNT];
-
- /**
- * All the objects in the pool are stored in a simple linked list
- */
- final LinkedList<E>[] items;
-
- /**
- * All threads waiting for an object are stored in a linked list
- */
- final LinkedList<ExchangeCountDownLatch<E>>[] waiters;
-
- /**
- * Creates a new fair blocking queue.
- */
- public MultiLockFairBlockingQueue() {
- items = new LinkedList[LOCK_COUNT];
- waiters = new LinkedList[LOCK_COUNT];
- for (int i=0; i<LOCK_COUNT; i++) {
- items[i] = new LinkedList<E>();
- waiters[i] = new LinkedList<ExchangeCountDownLatch<E>>();
- locks[i] = new ReentrantLock(false);
- }
- }
-
- //------------------------------------------------------------------
- // USED BY CONPOOL IMPLEMENTATION
- //------------------------------------------------------------------
- /**
- * Will always return true, queue is unbounded.
- * {@inheritDoc}
- */
- public boolean offer(E e) {
- int idx = getNextPut();
- //during the offer, we will grab the main lock
- final ReentrantLock lock = this.locks[idx];
- lock.lock();
- ExchangeCountDownLatch<E> c = null;
- try {
- //check to see if threads are waiting for an object
- if (waiters[idx].size() > 0) {
- //if threads are waiting grab the latch for that thread
- c = waiters[idx].poll();
- //give the object to the thread instead of adding it to the pool
- c.setItem(e);
- } else {
- //we always add first, so that the most recently used object will be given out
- items[idx].addFirst(e);
- }
- } finally {
- lock.unlock();
- }
- //if we exchanged an object with another thread, wake it up.
- if (c!=null) c.countDown();
- //we have an unbounded queue, so always return true
- return true;
- }
-
- /**
- * Will never timeout, as it invokes the {@link #offer(Object)} method.
- * Once a lock has been acquired, the
- * {@inheritDoc}
- */
- public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
- return offer(e);
- }
-
- /**
- * Fair retrieval of an object in the queue.
- * Objects are returned in the order the threads requested them.
- * {@inheritDoc}
- */
- public E poll(long timeout, TimeUnit unit) throws InterruptedException {
- int idx = getNextPoll();
- E result = null;
- final ReentrantLock lock = this.locks[idx];
- boolean error = true;
- //acquire the global lock until we know what to do
- lock.lock();
- try {
- //check to see if we have objects
- result = items[idx].poll();
- if (result==null && timeout>0) {
- //the queue is empty we will wait for an object
- ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<E>(1);
- //add to the bottom of the wait list
- waiters[idx].addLast(c);
- //unlock the global lock
- lock.unlock();
- //wait for the specified timeout
- if (!c.await(timeout, unit)) {
- //if we timed out, remove ourselves from the waitlist
- lock.lock();
- waiters[idx].remove(c);
- lock.unlock();
- }
- //return the item we received, can be null if we timed out
- result = c.getItem();
- } else {
- //we have an object, release
- lock.unlock();
- }
- error = false;
- } finally {
- if (error && lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- return result;
- }
-
- /**
- * Request an item from the queue asynchronously
- * @return - a future pending the result from the queue poll request
- */
- public Future<E> pollAsync() {
- int idx = getNextPoll();
- Future<E> result = null;
- final ReentrantLock lock = this.locks[idx];
- boolean error = true;
- //grab the global lock
- lock.lock();
- try {
- //check to see if we have objects in the queue
- E item = items[idx].poll();
- if (item==null) {
- //queue is empty, add ourselves as waiters
- ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<E>(1);
- waiters[idx].addLast(c);
- lock.unlock();
- //return a future that will wait for the object
- result = new ItemFuture<E>(c);
- } else {
- lock.unlock();
- //return a future with the item
- result = new ItemFuture<E>(item);
- }
- error = false;
- } finally {
- if (error && lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean remove(Object e) {
- for (int idx=0; idx<LOCK_COUNT; idx++) {
- final ReentrantLock lock = this.locks[idx];
- lock.lock();
- try {
- boolean result = items[idx].remove(e);
- if (result) return result;
- } finally {
- lock.unlock();
- }
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public int size() {
- int size = 0;
- for (int idx=0; idx<LOCK_COUNT; idx++) {
- size += items[idx].size();
- }
- return size;
- }
-
- /**
- * {@inheritDoc}
- */
- public Iterator<E> iterator() {
- return new FairIterator();
- }
-
- /**
- * {@inheritDoc}
- */
- public E poll() {
- int idx = getNextPoll();
- final ReentrantLock lock = this.locks[idx];
- lock.lock();
- try {
- return items[idx].poll();
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean contains(Object e) {
- for (int idx=0; idx<LOCK_COUNT; idx++) {
- boolean result = items[idx].contains(e);
- if (result) return result;
- }
- return false;
- }
-
-
- //------------------------------------------------------------------
- // NOT USED BY CONPOOL IMPLEMENTATION
- //------------------------------------------------------------------
- /**
- * {@inheritDoc}
- */
- public boolean add(E e) {
- return offer(e);
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public int drainTo(Collection<? super E> c, int maxElements) {
- throw new UnsupportedOperationException("int drainTo(Collection<? super E> c, int maxElements)");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public int drainTo(Collection<? super E> c) {
- return drainTo(c,Integer.MAX_VALUE);
- }
-
- /**
- * {@inheritDoc}
- */
- public void put(E e) throws InterruptedException {
- offer(e);
- }
-
- /**
- * {@inheritDoc}
- */
- public int remainingCapacity() {
- return Integer.MAX_VALUE - size();
- }
-
- /**
- * {@inheritDoc}
- */
- public E take() throws InterruptedException {
- return this.poll(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean addAll(Collection<? extends E> c) {
- Iterator<? extends E> i = c.iterator();
- while (i.hasNext()) {
- E e = i.next();
- offer(e);
- }
- return true;
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public void clear() {
- throw new UnsupportedOperationException("void clear()");
-
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public boolean containsAll(Collection<?> c) {
- throw new UnsupportedOperationException("boolean containsAll(Collection<?> c)");
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isEmpty() {
- return size() == 0;
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public boolean removeAll(Collection<?> c) {
- throw new UnsupportedOperationException("boolean removeAll(Collection<?> c)");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public boolean retainAll(Collection<?> c) {
- throw new UnsupportedOperationException("boolean retainAll(Collection<?> c)");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public Object[] toArray() {
- throw new UnsupportedOperationException("Object[] toArray()");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public <T> T[] toArray(T[] a) {
- throw new UnsupportedOperationException("<T> T[] toArray(T[] a)");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public E element() {
- throw new UnsupportedOperationException("E element()");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public E peek() {
- throw new UnsupportedOperationException("E peek()");
- }
-
- /**
- * {@inheritDoc}
- * @throws UnsupportedOperationException - this operation is not supported
- */
- public E remove() {
- throw new UnsupportedOperationException("E remove()");
- }
-
-
-
- //------------------------------------------------------------------
- // Non cancellable Future used to check and see if a connection has been made available
- //------------------------------------------------------------------
- protected class ItemFuture<T> implements Future<T> {
- protected volatile T item = null;
- protected volatile ExchangeCountDownLatch<T> latch = null;
- protected volatile boolean canceled = false;
-
- public ItemFuture(T item) {
- this.item = item;
- }
-
- public ItemFuture(ExchangeCountDownLatch<T> latch) {
- this.latch = latch;
- }
-
- public boolean cancel(boolean mayInterruptIfRunning) {
- return false; //don't allow cancel for now
- }
-
- public T get() throws InterruptedException, ExecutionException {
- if (item!=null) {
- return item;
- } else if (latch!=null) {
- latch.await();
- return latch.getItem();
- } else {
- throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
- }
- }
-
- public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- if (item!=null) {
- return item;
- } else if (latch!=null) {
- boolean timedout = !latch.await(timeout, unit);
- if (timedout) throw new TimeoutException();
- else return latch.getItem();
- } else {
- throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
- }
- }
-
- public boolean isCancelled() {
- return false;
- }
-
- public boolean isDone() {
- return (item!=null || latch.getItem()!=null);
- }
-
- }
-
- //------------------------------------------------------------------
- // Count down latch that can be used to exchange information
- //------------------------------------------------------------------
- protected class ExchangeCountDownLatch<T> extends CountDownLatch {
- protected volatile T item;
- public ExchangeCountDownLatch(int i) {
- super(i);
- }
- public T getItem() {
- return item;
- }
- public void setItem(T item) {
- this.item = item;
- }
- }
-
- //------------------------------------------------------------------
- // Iterator safe from concurrent modification exceptions
- //------------------------------------------------------------------
- protected class FairIterator implements Iterator<E> {
- E[] elements = null;
- int index;
- E element = null;
-
- public FairIterator() {
- ArrayList<E> list = new ArrayList<E>(MultiLockFairBlockingQueue.this.size());
- for (int idx=0; idx<LOCK_COUNT; idx++) {
- final ReentrantLock lock = MultiLockFairBlockingQueue.this.locks[idx];
- lock.lock();
- try {
- elements = (E[]) new Object[MultiLockFairBlockingQueue.this.items[idx].size()];
- MultiLockFairBlockingQueue.this.items[idx].toArray(elements);
-
- } finally {
- lock.unlock();
- }
- }
- index = 0;
- elements = (E[]) new Object[list.size()];
- list.toArray(elements);
- }
- public boolean hasNext() {
- return index<elements.length;
- }
-
- public E next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- element = elements[index++];
- return element;
- }
-
- public void remove() {
- for (int idx=0; idx<LOCK_COUNT; idx++) {
- final ReentrantLock lock = MultiLockFairBlockingQueue.this.locks[idx];
- lock.lock();
- try {
- boolean result = MultiLockFairBlockingQueue.this.items[idx].remove(elements[index]);
- if (result) break;
- } finally {
- lock.unlock();
- }
- }
-
- }
-
- }
-}
+++ /dev/null
-/*
- * 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.util.Properties;
-
-import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
-
-/**
- * A list of properties that are configurable for a connection pool.
- * The {@link DataSource} object also implements this interface so that it can be easily configured through
- * an IoC container without having to specify a secondary object with a setter method.
- * @author fhanik
- *
- */
-
-public interface PoolConfiguration {
-
- /**
- * JMX prefix for interceptors that register themselves with JMX
- */
- public static final String PKG_PREFIX = "org.apache.tomcat.jdbc.pool.interceptor.";
-
- /**
- * Connections that have been abandoned (timed out) wont get closed and reported up unless the number of connections in use are
- * above the percentage defined by abandonWhenPercentageFull.
- * The value should be between 0-100.
- * The default value is 0, which implies that connections are eligible for
- * closure as soon as removeAbandonedTimeout has been reached.
- * @param percentage a value between 0 and 100 to indicate when connections that have been abandoned/timed out are considered abandoned
- */
- public void setAbandonWhenPercentageFull(int percentage);
-
- /**
- * Connections that have been abandoned (timed out) wont get closed and reported up unless the number of connections in use are
- * above the percentage defined by abandonWhenPercentageFull.
- * The value should be between 0-100.
- * The default value is 0, which implies that connections are eligible for
- * closure as soon as removeAbandonedTimeout has been reached.
- * @return percentage - a value between 0 and 100 to indicate when connections that have been abandoned/timed out are considered abandoned
- */
- public int getAbandonWhenPercentageFull();
-
- /**
- * Returns true if a fair queue is being used by the connection pool
- * @return true if a fair waiting queue is being used
- */
- public boolean isFairQueue();
-
- /**
- * Set to true if you wish that calls to getConnection
- * should be treated fairly in a true FIFO fashion.
- * This uses the {@link FairBlockingQueue} implementation for the list of the idle connections.
- * The default value is true.
- * This flag is required when you want to use asynchronous connection retrieval.
- * @param fairQueue
- */
- public void setFairQueue(boolean fairQueue);
-
- /**
- * Property not used. Access is always allowed.
- * Access can be achieved by calling unwrap on the pooled connection. see {@link javax.sql.DataSource} interface
- * or call getConnection through reflection or cast the object as {@link javax.sql.PooledConnection}
- * @return true
- */
- public boolean isAccessToUnderlyingConnectionAllowed();
-
- /**
- * No-op
- * @param accessToUnderlyingConnectionAllowed parameter ignored
- */
- public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed);
-
- /**
- * The connection properties that will be sent to the JDBC driver when establishing new connections.
- * Format of the string is [propertyName=property;] <br/>
- * NOTE - The "user" and "password" properties will be passed explicitly, so they do not need to be included here.
- * The default value is null.
- */
- public String getConnectionProperties();
-
- /**
- * The properties that will be passed into {@link java.sql.Driver#connect(String, Properties)} method.
- * Username and password do not need to be stored here, they will be passed into the properties right before the connection is established.
- * @param connectionProperties properties - Format of the string is [propertyName=property;]*
- * Example: prop1=value1;prop2=value2
- */
- public void setConnectionProperties(String connectionProperties);
-
- /**
- * Returns the database properties that are passed into the {@link java.sql.Driver#connect(String, Properties)} method.
- * @return database properties that are passed into the {@link java.sql.Driver#connect(String, Properties)} method.
- */
- public Properties getDbProperties();
-
- /**
- * Overrides the database properties passed into the {@link java.sql.Driver#connect(String, Properties)} method.
- * @param dbProperties
- */
- public void setDbProperties(Properties dbProperties);
-
- /**
- * The default auto-commit state of connections created by this pool.
- * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
- * @return the default auto commit setting, null is Driver default.
- */
- public Boolean isDefaultAutoCommit();
-
- /**
- * The default auto-commit state of connections created by this pool.
- * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
- * @return the default auto commit setting, null is Driver default.
- */
- public Boolean getDefaultAutoCommit();
-
- /**
- * The default auto-commit state of connections created by this pool.
- * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
- * @param defaultAutoCommit default auto commit setting, null is Driver default.
- */
- public void setDefaultAutoCommit(Boolean defaultAutoCommit);
-
- /**
- * If non null, during connection creation the method {@link java.sql.Connection#setCatalog(String)} will be called with the set value.
- * @return the default catalog, null if not set and accepting the driver default.
- */
- public String getDefaultCatalog();
-
- /**
- * If non null, during connection creation the method {@link java.sql.Connection#setCatalog(String)} will be called with the set value.
- * @param defaultCatalog null if not set and accepting the driver default.
- */
- public void setDefaultCatalog(String defaultCatalog);
-
- /**
- * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
- * @return null if not set and accepting the driver default otherwise the read only value
- */
- public Boolean isDefaultReadOnly();
-
- /**
- * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
- * @return null if not set and accepting the driver default otherwise the read only value
- */
- public Boolean getDefaultReadOnly();
-
- /**
- * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
- * @param defaultReadOnly null if not set and accepting the driver default.
- */
- public void setDefaultReadOnly(Boolean defaultReadOnly);
-
-
- /**
- * Returns the default transaction isolation level. If set to {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} the method
- * {@link java.sql.Connection#setTransactionIsolation(int)} will not be called during connection creation.
- * @return driver transaction isolation level, or -1 {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} if not set.
- */
- public int getDefaultTransactionIsolation();
-
- /**
- * If set to {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} the method
- * {@link java.sql.Connection#setTransactionIsolation(int)} will not be called during connection creation. Otherwise the method
- * will be called with the isolation level set by this property.
- * @param defaultTransactionIsolation a value of {@link java.sql.Connection#TRANSACTION_NONE}, {@link java.sql.Connection#TRANSACTION_READ_COMMITTED},
- * {@link java.sql.Connection#TRANSACTION_READ_UNCOMMITTED}, {@link java.sql.Connection#TRANSACTION_REPEATABLE_READ},
- * {@link java.sql.Connection#TRANSACTION_SERIALIZABLE} or {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION}
- * The last value will not be set on the connection.
- */
- public void setDefaultTransactionIsolation(int defaultTransactionIsolation);
-
- /**
- * 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
- * @return fully qualified JDBC driver name.
- */
- public String getDriverClassName();
-
- /**
- * 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
- * @param driverClassName a fully qualified Java class name of a {@link java.sql.Driver} implementation.
- */
- public void setDriverClassName(String driverClassName);
-
- /**
- * Returns the number of connections that will be established when the connection pool is started.
- * Default value is 10
- * @return number of connections to be started when pool is started
- */
- public int getInitialSize();
-
- /**
- * Set the number of connections that will be established when the connection pool is started.
- * Default value is 10.
- * If this value exceeds {@link #setMaxActive(int)} it will automatically be lowered.
- * @param initialSize the number of connections to be established.
- *
- */
- public void setInitialSize(int initialSize);
-
- /**
- * boolean flag to set if stack traces should be logged 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 false.
- * @return true if the connection pool logs stack traces when connections are borrowed from the pool.
- */
- public boolean isLogAbandoned();
-
- /**
- * boolean flag to set if stack traces should be logged 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 false.
- * @param logAbandoned set to true if stack traces should be recorded when {@link DataSource#getConnection()} is called.
- */
- public void setLogAbandoned(boolean logAbandoned);
-
- /**
- * The maximum number of active connections that can be allocated from this pool at the same time. The default value is 100
- * @return the maximum number of connections used by this pool
- */
- public int getMaxActive();
-
- /**
- * The maximum number of active connections that can be allocated from this pool at the same time. The default value is 100
- * @param maxActive hard limit for number of managed connections by this pool
- */
- public void setMaxActive(int maxActive);
-
-
- /**
- * The maximum number of connections that should be kept in the idle pool if {@link #isPoolSweeperEnabled()} returns false.
- * If the If {@link #isPoolSweeperEnabled()} returns true, then the idle pool can grow up to {@link #getMaxActive}
- * and will be shrunk according to {@link #getMinEvictableIdleTimeMillis()} setting.
- * Default value is maxActive:100
- * @return the maximum number of idle connections.
- */
- public int getMaxIdle();
-
- /**
- * The maximum number of connections that should be kept in the idle pool if {@link #isPoolSweeperEnabled()} returns false.
- * If the If {@link #isPoolSweeperEnabled()} returns true, then the idle pool can grow up to {@link #getMaxActive}
- * and will be shrunk according to {@link #getMinEvictableIdleTimeMillis()} setting.
- * Default value is maxActive:100
- * @param maxIdle the maximum size of the idle pool
- */
- public void setMaxIdle(int maxIdle);
-
- /**
- * The maximum number of milliseconds that the pool will wait (when there are no available connections and the
- * {@link #getMaxActive} has been reached) for a connection to be returned
- * before throwing an exception. Default value is 30000 (30 seconds)
- * @return the number of milliseconds to wait for a connection to become available if the pool is maxed out.
- */
- public int getMaxWait();
-
- /**
- * The maximum number of milliseconds that the pool will wait (when there are no available connections and the
- * {@link #getMaxActive} has been reached) for a connection to be returned
- * before throwing an exception. Default value is 30000 (30 seconds)
- * @param maxWait the maximum number of milliseconds to wait.
- */
- public void setMaxWait(int maxWait);
-
- /**
- * The minimum amount of time an object must sit idle in the pool before it is eligible for eviction.
- * The default value is 60000 (60 seconds).
- * @return the minimum amount of idle time in milliseconds before a connection is considered idle and eligible for eviction.
- */
- public int getMinEvictableIdleTimeMillis();
-
- /**
- * The minimum amount of time an object must sit idle in the pool before it is eligible for eviction.
- * The default value is 60000 (60 seconds).
- * @param minEvictableIdleTimeMillis the number of milliseconds a connection must be idle to be eligible for eviction.
- */
- public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis);
-
- /**
- * 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 and connections get closed.
- * Default value is derived from {@link #getInitialSize()} (also see {@link #setTestWhileIdle(boolean)}
- * The idle pool will not shrink below this value during an eviction run, hence the number of actual connections
- * can be between {@link #getMinIdle()} and somewhere between {@link #getMaxIdle()} and {@link #getMaxActive()}
- * @return the minimum number of idle or established connections
- */
- public int getMinIdle();
-
- /**
- * 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 and connections get closed.
- * Default value is derived from {@link #getInitialSize()} (also see {@link #setTestWhileIdle(boolean)}
- * The idle pool will not shrink below this value during an eviction run, hence the number of actual connections
- * can be between {@link #getMinIdle()} and somewhere between {@link #getMaxIdle()} and {@link #getMaxActive()}
- *
- * @param minIdle the minimum number of idle or established connections
- */
- public void setMinIdle(int minIdle);
-
- /**
- * Returns the name of the connection pool. By default a JVM unique random name is assigned.
- * @return the name of the pool, should be unique in a JVM
- */
- public String getName();
-
- /**
- * Sets the name of the connection pool
- * @param name the name of the pool, should be unique in a runtime JVM
- */
- public void setName(String name);
-
- /**
- * Property not used
- * @return unknown value
- */
- public int getNumTestsPerEvictionRun();
-
- /**
- * Property not used
- * @param numTestsPerEvictionRun parameter ignored.
- */
- public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun);
-
- /**
- * Returns the password used when establishing connections to the database.
- * @return the password in string format
- */
- public String getPassword();
-
- /**
- * Sets the password to establish the connection with.
- * The password will be included as a database property with the name 'password'.
- * @param password
- * @see #getDbProperties()
- */
- public void setPassword(String password);
-
- /**
- * @see #getName()
- * @return name
- */
- public String getPoolName();
-
- /**
- * Returns the username used to establish the connection with
- * @return the username used to establish the connection with
- */
- public String getUsername();
-
- /**
- * Sets the username used to establish the connection with
- * It will also be a property called 'user' in the database properties.
- * @param username
- * @see #getDbProperties()
- */
- public void setUsername(String username);
-
-
- /**
- * boolean flag to remove abandoned connections if they exceed the removeAbandonedTimout.
- * If set to true a connection is considered abandoned and eligible for removal if it has
- * been in use longer than the {@link #getRemoveAbandonedTimeout()} and the condition for
- * {@link #getAbandonWhenPercentageFull()} is met.
- * Setting this to true can recover db connections from applications that fail to close a connection.
- * See also {@link #isLogAbandoned()} The default value is false.
- * @return true if abandoned connections can be closed and expelled out of the pool
- */
- public boolean isRemoveAbandoned();
-
- /**
- * boolean flag to remove abandoned connections if they exceed the removeAbandonedTimout.
- * If set to true a connection is considered abandoned and eligible for removal if it has
- * been in use longer than the {@link #getRemoveAbandonedTimeout()} and the condition for
- * {@link #getAbandonWhenPercentageFull()} is met.
- * Setting this to true can recover db connections from applications that fail to close a connection.
- * See also {@link #isLogAbandoned()} The default value is false.
- * @param removeAbandoned set to true if abandoned connections can be closed and expelled out of the pool
- */
- public void setRemoveAbandoned(boolean removeAbandoned);
-
- /**
- * The time in seconds before a connection can be considered abandoned.
- * The timer can be reset upon queries using an interceptor.
- * @param removeAbandonedTimeout the time in seconds before a used connection can be considered abandoned
- * @see org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
- */
- public void setRemoveAbandonedTimeout(int removeAbandonedTimeout);
-
- /**
- * The time in seconds before a connection can be considered abandoned.
- * The timer can be reset upon queries using an interceptor.
- * @see org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
- * @return the time in seconds before a used connection can be considered abandoned
- */
- public int getRemoveAbandonedTimeout();
-
- /**
- * 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 false
- * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
- * @return true if the connection is to be validated upon borrowing a connection from the pool
- * @see #getValidationInterval()
- */
- public boolean isTestOnBorrow();
-
- /**
- * 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 false
- * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
- * @param testOnBorrow set to true if validation should take place before a connection is handed out to the application
- * @see #getValidationInterval()
- */
- public void setTestOnBorrow(boolean testOnBorrow);
-
- /**
- * The indication of whether objects will be validated after being returned to the pool.
- * If the 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.
- * Default value is false
- * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
- * @return true if validation should take place after a connection is returned to the pool
- * @see #getValidationInterval()
- */
- public boolean isTestOnReturn();
-
- /**
- * The indication of whether objects will be validated after being returned to the pool.
- * If the 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.
- * Default value is false
- * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
- * @param testOnReturn true if validation should take place after a connection is returned to the pool
- * @see #getValidationInterval()
- */
- public void setTestOnReturn(boolean testOnReturn);
-
-
- /**
- * Set to true if query validation should take place while the connection is idle.
- * @return true if validation should take place during idle checks
- * @see #setTimeBetweenEvictionRunsMillis(int)
- */
- public boolean isTestWhileIdle();
-
- /**
- * Set to true if query validation should take place while the connection is idle.
- * @param testWhileIdle true if validation should take place during idle checks
- * @see #setTimeBetweenEvictionRunsMillis(int)
- */
- public void setTestWhileIdle(boolean testWhileIdle);
-
- /**
- * The number of milliseconds to sleep between runs of the idle connection validation, abandoned cleaner
- * and idle pool resizing. 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 connection and resize the idle pool.
- * The default value is 5000 (5 seconds)
- * @return the sleep time in between validations in milliseconds
- */
- public int getTimeBetweenEvictionRunsMillis();
-
- /**
- * The number of milliseconds to sleep between runs of the idle connection validation, abandoned cleaner
- * and idle pool resizing. 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 connection and resize the idle pool.
- * The default value is 5000 (5 seconds)
- * @param timeBetweenEvictionRunsMillis the sleep time in between validations in milliseconds
- */
- public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis);
-
- /**
- * The URL used to connect to the database
- * @return the configured URL for this connection pool
- * @see java.sql.Driver#connect(String, Properties)
- */
- public String getUrl();
-
- /**
- * Sets the URL used to connect to the database
- * @param url the configured URL for this connection pool
- * @see java.sql.Driver#connect(String, Properties)
- */
- public void setUrl(String url);
-
- /**
- * The SQL query that will be used to validate connections from this
- * pool before returning them to the caller or pool.
- * If specified, this query does not have to return any data,
- * it just can't throw a SQLException.
- * The default value is null.
- * Example values are SELECT 1(mysql),
- * select 1 from dual(oracle),
- * SELECT 1(MS Sql Server)
- * @return the query used for validation or null if no validation is performed
- */
- public String getValidationQuery();
-
- /**
- * The SQL query that will be used to validate connections from this
- * pool before returning them to the caller or pool.
- * If specified, this query does not have to return any data,
- * it just can't throw a SQLException.
- * The default value is null.
- * Example values are SELECT 1(mysql),
- * select 1 from dual(oracle),
- * SELECT 1(MS Sql Server)
- * @param validationQuery the query used for validation or null if no validation is performed
- */
- public void setValidationQuery(String validationQuery);
-
- /**
- * Return the name of the optional validator class - may be null.
- *
- * @return the name of the optional validator class - may be null
- */
- public String getValidatorClassName();
-
- /**
- * Set the name for an optional validator class which will be used in place of test queries. If set to
- * null, standard validation will be used.
- *
- * @param className the name of the optional validator class
- */
- public void setValidatorClassName(String className);
-
- /**
- * @return the optional validator object - may be null
- */
- public Validator getValidator();
-
- /**
- * 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 30000 (30 seconds).
- * @return the validation interval in milliseconds
- */
- public long getValidationInterval();
-
- /**
- * 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 30000 (30 seconds).
- * @param validationInterval the validation interval in milliseconds
- */
- public void setValidationInterval(long validationInterval);
-
- /**
- * A custom query to be run when a connection is first created. The default value is null.
- * This query only runs once per connection, and that is when a new connection is established to the database.
- * If this value is non null, it will replace the validation query during connection creation.
- * @return the init SQL used to run against the DB or null if not set
- */
- public String getInitSQL();
-
- /**
- * A custom query to be run when a connection is first created. The default value is null.
- * This query only runs once per connection, and that is when a new connection is established to the database.
- * If this value is non null, it will replace the validation query during connection creation.
- * @param initSQL the init SQL used to run against the DB or null if no query should be executed
- */
- public void setInitSQL(String initSQL);
-
- /**
- * Returns true if we should run the validation query when connecting to the database for the first time on a connection.
- * Normally this is always set to false, unless one wants to use the validationQuery as an init query.
- * @return true if we should run the validation query upon connect
- */
- public boolean isTestOnConnect();
-
- /**
- * Set to true if we should run the validation query when connecting to the database for the first time on a connection.
- * Normally this is always set to false, unless one wants to use the validationQuery as an init query.
- * Setting an {@link #setInitSQL(String)} will override this setting, as the init SQL will be used instead of the validation query
- * @param testOnConnect set to true if we should run the validation query upon connect
- */
- public void setTestOnConnect(boolean testOnConnect);
-
- /**
- * A semicolon separated list of classnames extending {@link org.apache.tomcat.jdbc.pool.JdbcInterceptor} class.
- * These interceptors will be inserted as an interceptor into the chain of operations on a java.sql.Connection object.
- * Example interceptors are {@link org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer StatementFinalizer} to close all
- * used statements during the session.
- * {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer ResetAbandonedTimer} resets the timer upon every operation
- * on the connection or a statement.
- * {@link org.apache.tomcat.jdbc.pool.interceptor.ConnectionState ConnectionState} caches the auto commit, read only and catalog settings to avoid round trips to the DB.
- * The default value is null.
- * @return the interceptors that are used for connections.
- * Example format: 'ConnectionState(useEquals=true,fast=yes);ResetAbandonedTimer'
- */
- public String getJdbcInterceptors();
-
- /**
- * A semicolon separated list of classnames extending {@link org.apache.tomcat.jdbc.pool.JdbcInterceptor} class.
- * These interceptors will be inserted as an interceptor into the chain of operations on a java.sql.Connection object.
- * Example interceptors are {@link org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer StatementFinalizer} to close all
- * used statements during the session.
- * {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer ResetAbandonedTimer} resets the timer upon every operation
- * on the connection or a statement.
- * {@link org.apache.tomcat.jdbc.pool.interceptor.ConnectionState ConnectionState} caches the auto commit, read only and catalog settings to avoid round trips to the DB.
- * The default value is null.
- * @param jdbcInterceptors the interceptors that are used for connections.
- * Example format: 'ConnectionState(useEquals=true,fast=yes);ResetAbandonedTimer'
- */
- public void setJdbcInterceptors(String jdbcInterceptors);
-
- /**
- * Returns the {@link #getJdbcInterceptors()} as an array of objects with properties and the classes.
- * @return an array of interceptors that have been configured
- */
- public InterceptorDefinition[] getJdbcInterceptorsAsArray();
-
-
- /**
- * If set to true, the connection pool creates a {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} object
- * that can be registered with JMX to receive notifications and state about the pool.
- * The ConnectionPool object doesn't register itself, as there is no way to keep a static non changing ObjectName across JVM restarts.
- * @return true if the mbean object will be created upon startup.
- */
- public boolean isJmxEnabled();
-
- /**
- * If set to true, the connection pool creates a {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} object
- * that can be registered with JMX to receive notifications and state about the pool.
- * The ConnectionPool object doesn't register itself, as there is no way to keep a static non changing ObjectName across JVM restarts.
- * @param jmxEnabled set to to if the mbean object should be created upon startup.
- */
- public void setJmxEnabled(boolean jmxEnabled);
-
- /**
- * Returns true if the pool sweeper is enabled for the connection pool.
- * The pool sweeper is enabled if any settings that require async intervention in the pool are turned on
- * <source>
- boolean result = getTimeBetweenEvictionRunsMillis()>0;
- result = result && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
- result = result || (isTestWhileIdle() && getValidationQuery()!=null);
- return result;
- </source>
- *
- * @return true if a background thread is or will be enabled for this pool
- */
- public boolean isPoolSweeperEnabled();
-
- /**
- * Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> instead of
- * <code>==</code> when comparing method names.
- * This property does not apply to added interceptors as those are configured individually.
- * The default value is <code>false</code>.
- * @return true if pool uses {@link String#equals(Object)} instead of == when comparing method names on {@link java.sql.Connection} methods
- */
- public boolean isUseEquals();
-
- /**
- * Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> instead of
- * <code>==</code> when comparing method names.
- * This property does not apply to added interceptors as those are configured individually.
- * The default value is <code>false</code>.
- * @param useEquals set to true if the pool should use {@link String#equals(Object)} instead of ==
- * when comparing method names on {@link java.sql.Connection} methods
- */
- public void setUseEquals(boolean useEquals);
-
- /**
- * Time in milliseconds to keep this connection alive even when used.
- * When a connection is returned to the pool, the pool will check to see if the
- * ((now - time-when-connected) > maxAge) has been reached, and if so,
- * it closes the connection rather than returning it to the pool.
- * The default value is 0, which implies that connections will be left open and no
- * age check will be done upon returning the connection to the pool.
- * This is a useful setting for database sessions that leak memory as it ensures that the session
- * will have a finite life span.
- * @return the time in milliseconds a connection will be open for when used
- */
- public long getMaxAge();
-
- /**
- * Time in milliseconds to keep this connection alive even when used.
- * When a connection is returned to the pool, the pool will check to see if the
- * ((now - time-when-connected) > maxAge) has been reached, and if so,
- * it closes the connection rather than returning it to the pool.
- * The default value is 0, which implies that connections will be left open and no
- * age check will be done upon returning the connection to the pool.
- * This is a useful setting for database sessions that leak memory as it ensures that the session
- * will have a finite life span.
- * @param maxAge the time in milliseconds a connection will be open for when used
- */
- public void setMaxAge(long maxAge);
-
- /**
- * Return true if a lock should be used when operations are performed on the connection object.
- * Should be set to false unless you plan to have a background thread of your own doing idle and abandon checking
- * such as JMX clients. If the pool sweeper is enabled, then the lock will automatically be used regardless of this setting.
- * @return true if a lock is used.
- */
- public boolean getUseLock();
-
- /**
- * Set to true if a lock should be used when operations are performed on the connection object.
- * Should be set to false unless you plan to have a background thread of your own doing idle and abandon checking
- * such as JMX clients. If the pool sweeper is enabled, then the lock will automatically be used regardless of this setting.
- * @param useLock set to true if a lock should be used on connection operations
- */
- public void setUseLock(boolean useLock);
-
- /**
- * Similar to {@link #setRemoveAbandonedTimeout(int)} but instead of treating the connection
- * as abandoned, and potentially closing the connection, this simply logs the warning if
- * {@link #isLogAbandoned()} returns true. If this value is equal or less than 0, no suspect
- * checking will be performed. Suspect checking only takes place if the timeout value is larger than 0 and
- * the connection was not abandoned or if abandon check is disabled. If a connection is suspect a WARN message gets
- * logged and a JMX notification gets sent once.
- * @param seconds - the amount of time in seconds that has to pass before a connection is marked suspect.
- */
- public void setSuspectTimeout(int seconds);
-
- /**
- * Returns the time in seconds to pass before a connection is marked an abanoned suspect.
- * Any value lesser than or equal to 0 means the check is disabled.
- * @return Returns the time in seconds to pass before a connection is marked an abanoned suspect.
- */
- public int getSuspectTimeout();
-
- /**
- * Injects a datasource that will be used to retrieve/create connections.
- * If a data source is set, the {@link PoolConfiguration#getUrl()} and {@link PoolConfiguration#getDriverClassName()} methods are ignored
- * and not used by the pool. If the {@link PoolConfiguration#getUsername()} and {@link PoolConfiguration#getPassword()}
- * values are set, the method {@link javax.sql.DataSource#getConnection(String, String)} method will be called instead of the
- * {@link javax.sql.DataSource#getConnection()} method.
- * If the data source implements {@link javax.sql.XADataSource} the methods
- * {@link javax.sql.XADataSource#getXAConnection()} and {@link javax.sql.XADataSource#getXAConnection(String,String)}
- * will be invoked.
- * @param ds the {@link javax.sql.DataSource} to be used for creating connections to be pooled.
- */
- public void setDataSource(Object ds);
-
- /**
- * Returns a datasource, if one exists that is being used to create connections.
- * This method will return null if the pool is using a {@link java.sql.Driver}
- * @return the {@link javax.sql.DataSource} to be used for creating connections to be pooled or null if a Driver is used.
- */
- public Object getDataSource();
-
- /**
- * Configure the connection pool to use a DataSource according to {@link PoolConfiguration#setDataSource(Object)}
- * But instead of injecting the object, specify the JNDI location.
- * After a successful JNDI look, the {@link PoolConfiguration#getDataSource()} will not return null.
- * @param jndiDS -the JNDI string @TODO specify the rules here.
- */
- public void setDataSourceJNDI(String jndiDS);
-
- /**
- * Returns the JNDI string configured for data source usage.
- * @return the JNDI string or null if not set
- */
- public String getDataSourceJNDI();
-
- /**
- * Returns true if the call {@link DataSource#getConnection(String, String) getConnection(username,password)} is
- * allowed. This is used for when the pool is used by an application accessing multiple schemas.
- * There is a performance impact turning this option on.
- * @return true if {@link DataSource#getConnection(String, String) getConnection(username,password)} is honored, false if it is ignored.
- */
- public boolean isAlternateUsernameAllowed();
-
- /**
- * Set to true if the call {@link DataSource#getConnection(String, String) getConnection(username,password)} is
- * allowed and honored.. This is used for when the pool is used by an application accessing multiple schemas.
- * There is a performance impact turning this option on, even when not used due to username checks.
- * @param alternateUsernameAllowed - set true if {@link DataSource#getConnection(String, String) getConnection(username,password)} is honored,
- * false if it is to be ignored.
- */
- public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed);
-
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.io.IOException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.atomic.AtomicInteger;
-
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-
-/**
- * @author Filip Hanik
- *
- */
-public class PoolProperties implements PoolConfiguration {
- private static final Log log = LogFactory.getLog(PoolProperties.class);
-
- public static final int DEFAULT_MAX_ACTIVE = 100;
-
- protected static AtomicInteger poolCounter = new AtomicInteger(0);
- 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 = DEFAULT_MAX_ACTIVE;
- protected int maxIdle = maxActive;
- protected int minIdle = initialSize;
- protected int maxWait = 30000;
- protected String validationQuery;
- protected String validatorClassName;
- protected Validator validator;
- protected boolean testOnBorrow = false;
- protected boolean testOnReturn = false;
- protected boolean testWhileIdle = false;
- protected int timeBetweenEvictionRunsMillis = 5000;
- protected int numTestsPerEvictionRun;
- protected int minEvictableIdleTimeMillis = 60000;
- protected final boolean accessToUnderlyingConnectionAllowed = true;
- protected boolean removeAbandoned = false;
- protected int removeAbandonedTimeout = 60;
- protected boolean logAbandoned = false;
- protected String name = "Tomcat Connection Pool["+(poolCounter.addAndGet(1))+"-"+System.identityHashCode(PoolProperties.class)+"]";
- protected String password;
- protected String username;
- protected long validationInterval = 30000;
- protected boolean jmxEnabled = true;
- protected String initSQL;
- protected boolean testOnConnect =false;
- protected String jdbcInterceptors=null;
- protected boolean fairQueue = true;
- protected boolean useEquals = true;
- protected int abandonWhenPercentageFull = 0;
- protected long maxAge = 0;
- protected boolean useLock = false;
- protected InterceptorDefinition[] interceptors = null;
- protected int suspectTimeout = 0;
- protected Object dataSource = null;
- protected String dataSourceJNDI = null;
- protected boolean alternateUsernameAllowed = false;
-
-
- /**
- * {@inheritDoc}
- */
-
- public void setAbandonWhenPercentageFull(int percentage) {
- if (percentage<0) abandonWhenPercentageFull = 0;
- else if (percentage>100) abandonWhenPercentageFull = 100;
- else abandonWhenPercentageFull = percentage;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getAbandonWhenPercentageFull() {
- return abandonWhenPercentageFull;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isFairQueue() {
- return fairQueue;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setFairQueue(boolean fairQueue) {
- this.fairQueue = fairQueue;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isAccessToUnderlyingConnectionAllowed() {
- return accessToUnderlyingConnectionAllowed;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getConnectionProperties() {
- return connectionProperties;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Properties getDbProperties() {
- return dbProperties;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Boolean isDefaultAutoCommit() {
- return defaultAutoCommit;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getDefaultCatalog() {
- return defaultCatalog;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Boolean isDefaultReadOnly() {
- return defaultReadOnly;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getDefaultTransactionIsolation() {
- return defaultTransactionIsolation;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getDriverClassName() {
- return driverClassName;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getInitialSize() {
- return initialSize;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isLogAbandoned() {
- return logAbandoned;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMaxActive() {
- return maxActive;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMaxIdle() {
- return maxIdle;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMaxWait() {
- return maxWait;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMinEvictableIdleTimeMillis() {
- return minEvictableIdleTimeMillis;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getMinIdle() {
- return minIdle;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getName() {
- return name;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getNumTestsPerEvictionRun() {
- return numTestsPerEvictionRun;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getPassword() {
- return password;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getPoolName() {
- return getName();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isRemoveAbandoned() {
- return removeAbandoned;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getRemoveAbandonedTimeout() {
- return removeAbandonedTimeout;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isTestOnBorrow() {
- return testOnBorrow;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isTestOnReturn() {
- return testOnReturn;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isTestWhileIdle() {
- return testWhileIdle;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getTimeBetweenEvictionRunsMillis() {
- return timeBetweenEvictionRunsMillis;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getUrl() {
- return url;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getUsername() {
- return username;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getValidationQuery() {
- return validationQuery;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getValidatorClassName() {
- return validatorClassName;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Validator getValidator() {
- return validator;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public long getValidationInterval() {
- return validationInterval;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getInitSQL() {
- return initSQL;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isTestOnConnect() {
- return testOnConnect;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getJdbcInterceptors() {
- return jdbcInterceptors;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
- if (interceptors == null) {
- if (jdbcInterceptors==null) {
- interceptors = new InterceptorDefinition[0];
- } else {
- String[] interceptorValues = jdbcInterceptors.split(";");
- InterceptorDefinition[] definitions = new InterceptorDefinition[interceptorValues.length];
- for (int i=0; i<interceptorValues.length; i++) {
- int propIndex = interceptorValues[i].indexOf("(");
- int endIndex = interceptorValues[i].indexOf(")");
- if (propIndex<0 || endIndex<0 || endIndex <= propIndex) {
- definitions[i] = new InterceptorDefinition(interceptorValues[i].trim());
- } else {
- String name = interceptorValues[i].substring(0,propIndex).trim();
- definitions[i] = new InterceptorDefinition(name);
- String propsAsString = interceptorValues[i].substring(propIndex+1, interceptorValues[i].length()-1);
- String[] props = propsAsString.split(",");
- for (int j=0; j<props.length; j++) {
- int pidx = props[j].indexOf("=");
- String propName = props[j].substring(0,pidx).trim();
- String propValue = props[j].substring(pidx+1).trim();
- definitions[i].addProperty(new InterceptorProperty(propName,propValue));
- }
- }
- }
- interceptors = definitions;
- }
- }
- return interceptors;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
- // NOOP
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setConnectionProperties(String connectionProperties) {
- this.connectionProperties = connectionProperties;
- getProperties(connectionProperties, getDbProperties());
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDbProperties(Properties dbProperties) {
- this.dbProperties = dbProperties;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
- this.defaultAutoCommit = defaultAutoCommit;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDefaultCatalog(String defaultCatalog) {
- this.defaultCatalog = defaultCatalog;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDefaultReadOnly(Boolean defaultReadOnly) {
- this.defaultReadOnly = defaultReadOnly;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
- this.defaultTransactionIsolation = defaultTransactionIsolation;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setDriverClassName(String driverClassName) {
- this.driverClassName = driverClassName;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setInitialSize(int initialSize) {
- this.initialSize = initialSize;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setLogAbandoned(boolean logAbandoned) {
- this.logAbandoned = logAbandoned;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMaxActive(int maxActive) {
- this.maxActive = maxActive;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMaxIdle(int maxIdle) {
- this.maxIdle = maxIdle;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMaxWait(int maxWait) {
- this.maxWait = maxWait;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
- this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMinIdle(int minIdle) {
- this.minIdle = minIdle;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
- this.numTestsPerEvictionRun = numTestsPerEvictionRun;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setRemoveAbandoned(boolean removeAbandoned) {
- this.removeAbandoned = removeAbandoned;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
- this.removeAbandonedTimeout = removeAbandonedTimeout;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTestOnBorrow(boolean testOnBorrow) {
- this.testOnBorrow = testOnBorrow;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTestWhileIdle(boolean testWhileIdle) {
- this.testWhileIdle = testWhileIdle;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTestOnReturn(boolean testOnReturn) {
- this.testOnReturn = testOnReturn;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTimeBetweenEvictionRunsMillis(int
- timeBetweenEvictionRunsMillis) {
- this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setValidationInterval(long validationInterval) {
- this.validationInterval = validationInterval;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setValidationQuery(String validationQuery) {
- this.validationQuery = validationQuery;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setValidatorClassName(String className) {
- this.validatorClassName = className;
-
- validator = null;
-
- if (className == null) {
- return;
- }
-
- try {
- Class<Validator> validatorClass = (Class<Validator>)Class.forName(className);
- validator = validatorClass.newInstance();
- } catch (ClassNotFoundException e) {
- log.warn("The class "+className+" cannot be found.", e);
- } catch (ClassCastException e) {
- log.warn("The class "+className+" does not implement the Validator interface.", e);
- } catch (InstantiationException e) {
- log.warn("An object of class "+className+" cannot be instantiated. Make sure that "+
- "it includes an implicit or explicit no-arg constructor.", e);
- } catch (IllegalAccessException e) {
- log.warn("The class "+className+" or its no-arg constructor are inaccessible.", e);
- }
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setInitSQL(String initSQL) {
- this.initSQL = initSQL;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setTestOnConnect(boolean testOnConnect) {
- this.testOnConnect = testOnConnect;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setJdbcInterceptors(String jdbcInterceptors) {
- this.jdbcInterceptors = jdbcInterceptors;
- this.interceptors = null;
- }
-
-
- public String toString() {
- StringBuilder buf = new StringBuilder("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.get();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isJmxEnabled() {
- return jmxEnabled;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setJmxEnabled(boolean jmxEnabled) {
- this.jmxEnabled = jmxEnabled;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Boolean getDefaultAutoCommit() {
- return defaultAutoCommit;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Boolean getDefaultReadOnly() {
- return defaultReadOnly;
- }
-
-
- /**
- * {@inheritDoc}
- */
-
- public int getSuspectTimeout() {
- return this.suspectTimeout;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setSuspectTimeout(int seconds) {
- this.suspectTimeout = seconds;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isPoolSweeperEnabled() {
- boolean timer = getTimeBetweenEvictionRunsMillis()>0;
- boolean result = timer && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
- result = result || (timer && getSuspectTimeout()>0);
- result = result || (timer && isTestWhileIdle() && getValidationQuery()!=null);
- result = result || (timer && getMinEvictableIdleTimeMillis()>0);
- return result;
- }
-
-
- public static class InterceptorDefinition {
- protected String className;
- protected Map<String,InterceptorProperty> properties = new HashMap<String,InterceptorProperty>();
- protected volatile Class<?> clazz = null;
- public InterceptorDefinition(String className) {
- this.className = className;
- }
-
- public String getClassName() {
- return className;
- }
- public void addProperty(String name, String value) {
- InterceptorProperty p = new InterceptorProperty(name,value);
- addProperty(p);
- }
-
- public void addProperty(InterceptorProperty p) {
- properties.put(p.getName(), p);
- }
-
- public Map<String,InterceptorProperty> getProperties() {
- return properties;
- }
-
- public Class<? extends JdbcInterceptor> getInterceptorClass() throws ClassNotFoundException {
- if (clazz==null) {
- if (getClassName().indexOf(".")<0) {
- if (log.isDebugEnabled()) {
- log.debug("Loading interceptor class:"+PoolConfiguration.PKG_PREFIX+getClassName());
- }
- clazz = Class.forName(PoolConfiguration.PKG_PREFIX+getClassName(), true, this.getClass().getClassLoader());
- } else {
- if (log.isDebugEnabled()) {
- log.debug("Loading interceptor class:"+getClassName());
- }
- clazz = Class.forName(getClassName(), true, this.getClass().getClassLoader());
- }
- }
- return (Class<? extends JdbcInterceptor>)clazz;
- }
- }
-
- public static class InterceptorProperty {
- String name;
- String value;
- public InterceptorProperty(String name, String value) {
- assert(name!=null);
- this.name = name;
- this.value = value;
- }
- public String getName() {
- return name;
- }
- public String getValue() {
- return value;
- }
-
- public boolean getValueAsBoolean(boolean def) {
- if (value==null) return def;
- if ("true".equals(value)) return true;
- if ("false".equals(value)) return false;
- return def;
- }
-
- public int getValueAsInt(int def) {
- if (value==null) return def;
- try {
- int v = Integer.parseInt(value);
- return v;
- }catch (NumberFormatException nfe) {
- return def;
- }
- }
-
- public long getValueAsLong(long def) {
- if (value==null) return def;
- try {
- return Long.parseLong(value);
- }catch (NumberFormatException nfe) {
- return def;
- }
- }
-
- public byte getValueAsByte(byte def) {
- if (value==null) return def;
- try {
- return Byte.parseByte(value);
- }catch (NumberFormatException nfe) {
- return def;
- }
- }
-
- public short getValueAsShort(short def) {
- if (value==null) return def;
- try {
- return Short.parseShort(value);
- }catch (NumberFormatException nfe) {
- return def;
- }
- }
-
- public float getValueAsFloat(float def) {
- if (value==null) return def;
- try {
- return Float.parseFloat(value);
- }catch (NumberFormatException nfe) {
- return def;
- }
- }
-
- public double getValueAsDouble(double def) {
- if (value==null) return def;
- try {
- return Double.parseDouble(value);
- }catch (NumberFormatException nfe) {
- return def;
- }
- }
-
- public char getValueAschar(char def) {
- if (value==null) return def;
- try {
- return value.charAt(0);
- }catch (StringIndexOutOfBoundsException nfe) {
- return def;
- }
- }
-
- public int hashCode() {
- return name.hashCode();
- }
-
- public boolean equals(Object o) {
- if (o==this) return true;
- if (o instanceof InterceptorProperty) {
- InterceptorProperty other = (InterceptorProperty)o;
- return other.name.equals(this.name);
- }
- return false;
- }
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean isUseEquals() {
- return useEquals;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setUseEquals(boolean useEquals) {
- this.useEquals = useEquals;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public long getMaxAge() {
- return maxAge;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setMaxAge(long maxAge) {
- this.maxAge = maxAge;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public boolean getUseLock() {
- return useLock;
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setUseLock(boolean useLock) {
- this.useLock = useLock;
- }
-
-
- /**
- * {@inheritDoc}
- */
- public void setDataSource(Object ds) {
- this.dataSource = ds;
- }
-
- /**
- * {@inheritDoc}
- */
- public Object getDataSource() {
- return dataSource;
- }
-
-
- /**
- * {@inheritDoc}
- */
- public void setDataSourceJNDI(String jndiDS) {
- this.dataSourceJNDI = jndiDS;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getDataSourceJNDI() {
- return this.dataSourceJNDI;
- }
-
-
- public static Properties getProperties(String propText, Properties props) {
- if (props==null) props = new Properties();
- if (propText != null) {
- try {
- props.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
- }catch (IOException x) {
- throw new RuntimeException(x);
- }
- }
- return props;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isAlternateUsernameAllowed() {
- return alternateUsernameAllowed;
- }
-
- /**
- * {@inheritDoc}
- */
- public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
- this.alternateUsernameAllowed = alternateUsernameAllowed;
- }
-
-}
+++ /dev/null
-/*
- * 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.util.Properties;
-
-/**
- *
- * @author fhanik
- *
- */
-public class PoolUtilities {
-
- public static final String PROP_USER = "user";
-
- public static final String PROP_PASSWORD = "password";
-
- public static Properties clone(Properties p) {
- Properties c = new Properties();
- c.putAll(p);
- return c;
- }
-
- public static Properties cloneWithoutPassword(Properties p) {
- Properties result = clone(p);
- result.remove(PROP_PASSWORD);
- return result;
- }
-}
+++ /dev/null
-/*
- * 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.SQLException;
-import java.sql.Statement;
-import java.util.HashMap;
-import java.util.Properties;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Represents a pooled connection
- * and holds a reference to the {@link java.sql.Connection} object
- * @author Filip Hanik
- * @version 1.0
- */
-public class PooledConnection {
- /**
- * Logger
- */
- private static final Log log = LogFactory.getLog(PooledConnection.class);
-
- public static final String PROP_USER = PoolUtilities.PROP_USER;
-
- public static final String PROP_PASSWORD = PoolUtilities.PROP_PASSWORD;
-
- /**
- * Validate when connection is borrowed flag
- */
- public static final int VALIDATE_BORROW = 1;
- /**
- * Validate when connection is returned flag
- */
- public static final int VALIDATE_RETURN = 2;
- /**
- * Validate when connection is idle flag
- */
- public static final int VALIDATE_IDLE = 3;
- /**
- * Validate when connection is initialized flag
- */
- public static final int VALIDATE_INIT = 4;
- /**
- * The properties for the connection pool
- */
- protected PoolConfiguration poolProperties;
- /**
- * The underlying database connection
- */
- private volatile java.sql.Connection connection;
-
- /**
- * If using a XAConnection underneath.
- */
- protected volatile javax.sql.XAConnection xaConnection;
- /**
- * When we track abandon traces, this string holds the thread dump
- */
- private String abandonTrace = null;
- /**
- * Timestamp the connection was last 'touched' by the pool
- */
- private volatile long timestamp;
- /**
- * Lock for this connection only
- */
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
- /**
- * Set to true if this connection has been discarded by the pool
- */
- private volatile boolean discarded = false;
- /**
- * The Timestamp when the last time the connect() method was called successfully
- */
- private volatile long lastConnected = -1;
- /**
- * timestamp to keep track of validation intervals
- */
- private volatile long lastValidated = System.currentTimeMillis();
- /**
- * The parent
- */
- protected ConnectionPool parent;
-
- private HashMap<Object, Object> attributes = new HashMap<Object, Object>();
-
- /**
- * Weak reference to cache the list of interceptors for this connection
- * so that we don't create a new list of interceptors each time we borrow
- * the connection
- */
- private volatile JdbcInterceptor handler = null;
-
- private AtomicBoolean released = new AtomicBoolean(false);
-
- private volatile boolean suspect = false;
-
- private java.sql.Driver driver = null;
-
- /**
- * Constructor
- * @param prop - pool properties
- * @param parent - the parent connection pool
- */
- public PooledConnection(PoolConfiguration prop, ConnectionPool parent) {
- poolProperties = prop;
- this.parent = parent;
- }
-
- public boolean checkUser(String username, String password) {
- if (!getPoolProperties().isAlternateUsernameAllowed()) return true;
-
- if (username==null) username = poolProperties.getUsername();
- if (password==null) password = poolProperties.getPassword();
-
- String storedUsr = (String)getAttributes().get(PROP_USER);
- String storedPwd = (String)getAttributes().get(PROP_PASSWORD);
-
- boolean result = (username==null && storedUsr==null);
- result = (result || (username!=null && username.equals(storedUsr)));
-
- result = result && ((password==null && storedPwd==null) || (password!=null && password.equals(storedPwd)));
-
- if (username==null) getAttributes().remove(PROP_USER); else getAttributes().put(PROP_USER, username);
- if (password==null) getAttributes().remove(PROP_PASSWORD); else getAttributes().put(PROP_PASSWORD, password);
-
- return result;
- }
-
- /**
- * Connects the underlying connection to the database.
- * @throws SQLException if the method {@link #release()} has been called.
- * @throws SQLException if driver instantiation fails
- * @throws SQLException if a call to {@link java.sql.Driver#connect(String, java.util.Properties)} fails.
- * @throws SQLException if default properties are configured and a call to
- * {@link java.sql.Connection#setAutoCommit(boolean)}, {@link java.sql.Connection#setCatalog(String)},
- * {@link java.sql.Connection#setTransactionIsolation(int)} or {@link java.sql.Connection#setReadOnly(boolean)} fails.
- */
- public void connect() throws SQLException {
- if (released.get()) throw new SQLException("A connection once released, can't be reestablished.");
- if (connection != null) {
- try {
- this.disconnect(false);
- } catch (Exception x) {
- log.debug("Unable to disconnect previous connection.", x);
- } //catch
- } //end if
- if (poolProperties.getDataSource()==null && poolProperties.getDataSourceJNDI()!=null) {
- //TODO lookup JNDI name
- }
-
- if (poolProperties.getDataSource()!=null) {
- connectUsingDataSource();
- } else {
- connectUsingDriver();
- }
-
- //set up the default state, unless we expect the interceptor to do it
- if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0) {
- if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
- 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());
- }
- this.discarded = false;
- this.lastConnected = System.currentTimeMillis();
- }
-
- protected void connectUsingDataSource() throws SQLException {
- String usr = null;
- String pwd = null;
- if (getAttributes().containsKey(PROP_USER)) {
- usr = (String) getAttributes().get(PROP_USER);
- } else {
- usr = poolProperties.getUsername();
- getAttributes().put(PROP_USER, usr);
- }
- if (getAttributes().containsKey(PROP_PASSWORD)) {
- pwd = (String) getAttributes().get(PROP_PASSWORD);
- } else {
- pwd = poolProperties.getPassword();
- getAttributes().put(PROP_PASSWORD, pwd);
- }
- if (poolProperties.getDataSource() instanceof javax.sql.XADataSource) {
- javax.sql.XADataSource xds = (javax.sql.XADataSource)poolProperties.getDataSource();
- if (usr!=null && pwd!=null) {
- xaConnection = xds.getXAConnection(usr, pwd);
- connection = xaConnection.getConnection();
- } else {
- xaConnection = xds.getXAConnection();
- connection = xaConnection.getConnection();
- }
- } else if (poolProperties.getDataSource() instanceof javax.sql.DataSource){
- javax.sql.DataSource ds = (javax.sql.DataSource)poolProperties.getDataSource();
- if (usr!=null && pwd!=null) {
- connection = ds.getConnection(usr, pwd);
- } else {
- connection = ds.getConnection();
- }
- } else if (poolProperties.getDataSource() instanceof javax.sql.ConnectionPoolDataSource){
- javax.sql.ConnectionPoolDataSource ds = (javax.sql.ConnectionPoolDataSource)poolProperties.getDataSource();
- if (usr!=null && pwd!=null) {
- connection = ds.getPooledConnection(usr, pwd).getConnection();
- } else {
- connection = ds.getPooledConnection().getConnection();
- }
- } else {
- throw new SQLException("DataSource is of unknown class:"+(poolProperties.getDataSource()!=null?poolProperties.getDataSource().getClass():"null"));
- }
- }
- protected void connectUsingDriver() throws SQLException {
-
- try {
- if (driver==null)
- driver = (java.sql.Driver) Class.forName(poolProperties.getDriverClassName(),
- true, PooledConnection.class.getClassLoader()
- ).newInstance();
- } catch (java.lang.Exception cn) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to instantiate JDBC driver.", cn);
- }
- SQLException ex = new SQLException(cn.getMessage());
- ex.initCause(cn);
- throw ex;
- }
- String driverURL = poolProperties.getUrl();
- String usr = null;
- String pwd = null;
- if (getAttributes().containsKey(PROP_USER)) {
- usr = (String) getAttributes().get(PROP_USER);
- } else {
- usr = poolProperties.getUsername();
- getAttributes().put(PROP_USER, usr);
- }
- if (getAttributes().containsKey(PROP_PASSWORD)) {
- pwd = (String) getAttributes().get(PROP_PASSWORD);
- } else {
- pwd = poolProperties.getPassword();
- getAttributes().put(PROP_PASSWORD, pwd);
- }
- Properties properties = PoolUtilities.clone(poolProperties.getDbProperties());
- if (usr != null) properties.setProperty(PROP_USER, usr);
- if (pwd != null) properties.setProperty(PROP_PASSWORD, pwd);
-
- try {
- connection = connection = driver.connect(driverURL, properties);
- } catch (Exception x) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to connect to database.", x);
- }
- if (parent.jmxPool!=null) {
- parent.jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_CONNECT,
- ConnectionPool.getStackTrace(x));
- }
- if (x instanceof SQLException) {
- throw (SQLException)x;
- } else {
- SQLException ex = new SQLException(x.getMessage());
- ex.initCause(x);
- throw ex;
- }
- }
- if (connection==null) {
- throw new SQLException("Driver:"+driver+" returned null for URL:"+driverURL);
- }
- }
-
- /**
- *
- * @return true if connect() was called successfully and disconnect has not yet been called
- */
- public boolean isInitialized() {
- return connection!=null;
- }
-
- /**
- * Issues a call to {@link #disconnect(boolean)} with the argument false followed by a call to
- * {@link #connect()}
- * @throws SQLException if the call to {@link #connect()} fails.
- */
- public void reconnect() throws SQLException {
- this.disconnect(false);
- this.connect();
- } //reconnect
-
- /**
- * Disconnects the connection. All exceptions are logged using debug level.
- * @param finalize if set to true, a call to {@link ConnectionPool#finalize(PooledConnection)} is called.
- */
- private void disconnect(boolean finalize) {
- if (isDiscarded()) {
- return;
- }
- setDiscarded(true);
- if (connection != null) {
- try {
- parent.disconnectEvent(this, finalize);
- if (xaConnection == null) {
- connection.close();
- } else {
- xaConnection.close();
- }
- }catch (Exception ignore) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to close underlying SQL connection",ignore);
- }
- }
- }
- connection = null;
- xaConnection = null;
- lastConnected = -1;
- if (finalize) parent.finalize(this);
- }
-
-
-//============================================================================
-//
-//============================================================================
-
- /**
- * Returns abandon timeout in milliseconds
- * @return abandon timeout in milliseconds
- */
- public long getAbandonTimeout() {
- if (poolProperties.getRemoveAbandonedTimeout() <= 0) {
- return Long.MAX_VALUE;
- } else {
- return poolProperties.getRemoveAbandonedTimeout()*1000;
- } //end if
- }
-
- /**
- * Returns true if the connection pool is configured
- * to do validation for a certain action.
- * @param action
- * @return
- */
- private 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);
- }
-
- /**
- * Validates a connection.
- * @param validateAction the action used. One of {@link #VALIDATE_BORROW}, {@link #VALIDATE_IDLE},
- * {@link #VALIDATE_INIT} or {@link #VALIDATE_RETURN}
- * @param sql the SQL to be used during validation. If the {@link PoolConfiguration#setInitSQL(String)} has been called with a non null
- * value and the action is {@link #VALIDATE_INIT} the init SQL will be used for validation.
- *
- * @return true if the connection was validated successfully. It returns true even if validation was not performed, such as when
- * {@link PoolConfiguration#setValidationInterval(long)} has been called with a positive value.
- * <p>
- * false if the validation failed. The caller should close the connection if false is returned since a session could have been left in
- * an unknown state during initialization.
- */
- public boolean validate(int validateAction,String sql) {
- if (this.isDiscarded()) {
- return false;
- }
-
- if (!doValidate(validateAction)) {
- //no validation required, no init sql and props not set
- return true;
- }
-
- //Don't bother validating if already have recently enough
- long now = System.currentTimeMillis();
- if (validateAction!=VALIDATE_INIT &&
- poolProperties.getValidationInterval() > 0 &&
- (now - this.lastValidated) <
- poolProperties.getValidationInterval()) {
- return true;
- }
-
- if (poolProperties.getValidator() != null) {
- if (poolProperties.getValidator().validate(connection, validateAction)) {
- this.lastValidated = now;
- return true;
- } else {
- return false;
- }
- }
-
- String query = sql;
-
- if (validateAction == VALIDATE_INIT && poolProperties.getInitSQL() != null) {
- query = poolProperties.getInitSQL();
- }
-
- if (query == null) {
- query = poolProperties.getValidationQuery();
- }
-
- Statement stmt = null;
- try {
- stmt = connection.createStatement();
- stmt.execute(query);
- stmt.close();
- this.lastValidated = now;
- return true;
- } catch (Exception ignore) {
- if (log.isDebugEnabled())
- log.debug("Unable to validate object:",ignore);
- if (stmt!=null)
- try { stmt.close();} catch (Exception ignore2){/*NOOP*/}
- }
- return false;
- } //validate
-
- /**
- * The time limit for how long the object
- * can remain unused before it is released
- * @return {@link PoolConfiguration#getMinEvictableIdleTimeMillis()}
- */
- public long getReleaseTime() {
- return this.poolProperties.getMinEvictableIdleTimeMillis();
- }
-
- /**
- * This method is called if (Now - timeCheckedIn > getReleaseTime())
- * This method disconnects the connection, logs an error in debug mode if it happens
- * then sets the {@link #released} flag to false. Any attempts to connect this cached object again
- * will fail per {@link #connect()}
- * The connection pool uses the atomic return value to decrement the pool size counter.
- * @return true if this is the first time this method has been called. false if this method has been called before.
- */
- public boolean release() {
- try {
- disconnect(true);
- } catch (Exception x) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to close SQL connection",x);
- }
- }
- return released.compareAndSet(false, true);
-
- }
-
- /**
- * The pool will set the stack trace when it is check out and
- * checked in
- * @param trace the stack trace for this connection
- */
-
- public void setStackTrace(String trace) {
- abandonTrace = trace;
- }
-
- /**
- * Returns the stack trace from when this connection was borrowed. Can return null if no stack trace was set.
- * @return the stack trace or null of no trace was set
- */
- public String getStackTrace() {
- return abandonTrace;
- }
-
- /**
- * Sets a timestamp on this connection. A timestamp usually means that some operation
- * performed successfully.
- * @param timestamp the timestamp as defined by {@link System#currentTimeMillis()}
- */
- public void setTimestamp(long timestamp) {
- this.timestamp = timestamp;
- setSuspect(false);
- }
-
-
- public boolean isSuspect() {
- return suspect;
- }
-
- public void setSuspect(boolean suspect) {
- this.suspect = suspect;
- }
-
- /**
- * An interceptor can call this method with the value true, and the connection will be closed when it is returned to the pool.
- * @param discarded - only valid value is true
- * @throws IllegalStateException if this method is called with the value false and the value true has already been set.
- */
- 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;
- }
-
- /**
- * Set the timestamp the connection was last validated.
- * This flag is used to keep track when we are using a {@link PoolConfiguration#setValidationInterval(long) validation-interval}.
- * @param lastValidated a timestamp as defined by {@link System#currentTimeMillis()}
- */
- public void setLastValidated(long lastValidated) {
- this.lastValidated = lastValidated;
- }
-
- /**
- * Sets the pool configuration for this connection and connection pool.
- * Object is shared with the {@link ConnectionPool}
- * @param poolProperties
- */
- public void setPoolProperties(PoolConfiguration poolProperties) {
- this.poolProperties = poolProperties;
- }
-
- /**
- * Return the timestamps of last pool action. Timestamps are typically set when connections
- * are borrowed from the pool. It is used to keep track of {@link PoolConfiguration#setRemoveAbandonedTimeout(int) abandon-timeouts}.
- * This timestamp can also be reset by the {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer#invoke(Object, java.lang.reflect.Method, Object[])}
- * @return the timestamp of the last pool action as defined by {@link System#currentTimeMillis()}
- */
- public long getTimestamp() {
- return timestamp;
- }
-
- /**
- * Returns the discarded flag.
- * @return the discarded flag. If the value is true,
- * either {@link #disconnect(boolean)} has been called or it will be called when the connection is returned to the pool.
- */
- public boolean isDiscarded() {
- return discarded;
- }
-
- /**
- * Returns the timestamp of the last successful validation query execution.
- * @return the timestamp of the last successful validation query execution as defined by {@link System#currentTimeMillis()}
- */
- public long getLastValidated() {
- return lastValidated;
- }
-
- /**
- * Returns the configuration for this connection and pool
- * @return the configuration for this connection and pool
- */
- public PoolConfiguration getPoolProperties() {
- return poolProperties;
- }
-
- /**
- * Locks the connection only if either {@link PoolConfiguration#isPoolSweeperEnabled()} or
- * {@link PoolConfiguration#getUseLock()} return true. The per connection lock ensures thread safety is
- * multiple threads are performing operations on the connection.
- * Otherwise this is a noop for performance
- */
- public void lock() {
- if (poolProperties.getUseLock() || this.poolProperties.isPoolSweeperEnabled()) {
- //optimized, only use a lock when there is concurrency
- lock.writeLock().lock();
- }
- }
-
- /**
- * Unlocks the connection only if the sweeper is enabled
- * Otherwise this is a noop for performance
- */
- public void unlock() {
- if (poolProperties.getUseLock() || this.poolProperties.isPoolSweeperEnabled()) {
- //optimized, only use a lock when there is concurrency
- lock.writeLock().unlock();
- }
- }
-
- /**
- * Returns the underlying connection
- * @return the underlying JDBC connection as it was returned from the JDBC driver
- * @see javax.sql.PooledConnection#getConnection()
- */
- public java.sql.Connection getConnection() {
- return this.connection;
- }
-
- /**
- * Returns the underlying XA connection
- * @return the underlying XA connection as it was returned from the Datasource
- */
- public javax.sql.XAConnection getXAConnection() {
- return this.xaConnection;
- }
-
-
- /**
- * Returns the timestamp of when the connection was last connected to the database.
- * ie, a successful call to {@link java.sql.Driver#connect(String, java.util.Properties)}.
- * @return the timestamp when this connection was created as defined by {@link System#currentTimeMillis()}
- */
- public long getLastConnected() {
- return lastConnected;
- }
-
- /**
- * Returns the first handler in the interceptor chain
- * @return the first interceptor for this connection
- */
- public JdbcInterceptor getHandler() {
- return handler;
- }
-
- public void setHandler(JdbcInterceptor handler) {
- if (this.handler!=null && this.handler!=handler) {
- JdbcInterceptor interceptor = this.handler;
- while (interceptor!=null) {
- interceptor.reset(null, null);
- interceptor = interceptor.getNext();
- }//while
- }//end if
- this.handler = handler;
- }
-
- @Override
- public String toString() {
- return "PooledConnection["+(connection!=null?connection.toString():"null")+"]";
- }
-
- /**
- * Returns true if this connection has been released and wont be reused.
- * @return true if the method {@link #release()} has been called
- */
- public boolean isReleased() {
- return released.get();
- }
-
- public HashMap<Object,Object> getAttributes() {
- return attributes;
- }
-
-}
+++ /dev/null
-/*
- * 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.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.sql.SQLException;
-
-import javax.sql.XAConnection;
-/**
- * A ProxyConnection object is the bottom most interceptor that wraps an object of type
- * {@link PooledConnection}. The ProxyConnection intercepts three methods:
- * <ul>
- * <li>{@link java.sql.Connection#close()} - returns the connection to the pool. May be called multiple times.</li>
- * <li>{@link java.lang.Object#toString()} - returns a custom string for this object</li>
- * <li>{@link javax.sql.PooledConnection#getConnection()} - returns the underlying connection</li>
- * </ul>
- * By default method comparisons is done on a String reference level, unless the {@link PoolConfiguration#setUseEquals(boolean)} has been called
- * with a <code>true</code> argument.
- * @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, boolean useEquals) throws SQLException {
- pool = parent;
- connection = con;
- setUseEquals(useEquals);
- }
-
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- this.pool = parent;
- this.connection = con;
- }
-
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- if (iface == XAConnection.class && connection.getXAConnection()!=null) {
- return true;
- } else {
- return (iface.isInstance(connection.getConnection()));
- }
- }
-
-
- public Object unwrap(Class<?> iface) throws SQLException {
- if (iface == PooledConnection.class) {
- return connection;
- }else if (iface == XAConnection.class) {
- return connection.getXAConnection();
- } else if (isWrapperFor(iface)) {
- return connection.getConnection();
- } else {
- throw new SQLException("Not a wrapper of "+iface.getName());
- }
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (compare(ISCLOSED_VAL,method)) {
- return Boolean.valueOf(isClosed());
- }
- if (compare(CLOSE_VAL,method)) {
- if (isClosed()) return null; //noop for already closed.
- PooledConnection poolc = this.connection;
- this.connection = null;
- pool.returnConnection(poolc);
- return null;
- } else if (compare(TOSTRING_VAL,method)) {
- return this.toString();
- } else if (compare(GETCONNECTION_VAL,method) && connection!=null) {
- return connection.getConnection();
- } else if (method.getDeclaringClass().equals(XAConnection.class)) {
- try {
- return method.invoke(connection.getXAConnection(),args);
- }catch (Throwable t) {
- if (t instanceof InvocationTargetException) {
- InvocationTargetException it = (InvocationTargetException)t;
- throw it.getCause()!=null?it.getCause():it;
- } else {
- throw t;
- }
- }
- }
- if (isClosed()) throw new SQLException("Connection has already been closed.");
- if (compare(UNWRAP_VAL,method)) {
- return unwrap((Class<?>)args[0]);
- } else if (compare(ISWRAPPERFOR_VAL,method)) {
- return this.isWrapperFor((Class<?>)args[0]);
- }
- try {
- return method.invoke(connection.getConnection(),args);
- }catch (Throwable t) {
- if (t instanceof InvocationTargetException) {
- InvocationTargetException it = (InvocationTargetException)t;
- throw it.getCause()!=null?it.getCause():it;
- } else {
- throw t;
- }
- }
- }
-
- public boolean isClosed() {
- return connection==null || connection.isDiscarded();
- }
-
- public PooledConnection getDelegateConnection() {
- return connection;
- }
-
- public ConnectionPool getParentPool() {
- return pool;
- }
-
- @Override
- public String toString() {
- return "ProxyConnection["+(connection!=null?connection.toString():"null")+"]";
- }
-
-}
+++ /dev/null
-/*
- * 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;
-
-/**
- * Interface to be implemented by custom validator classes.
- *
- * @author mpassell
- */
-public interface Validator {
- /**
- * Validate a connection and return a boolean to indicate if it's valid.
- *
- * @param connection the Connection object to test
- * @param validateAction the action used. One of {@link PooledConnection#VALIDATE_BORROW},
- * {@link PooledConnection#VALIDATE_IDLE}, {@link PooledConnection#VALIDATE_INIT} or
- * {@link PooledConnection#VALIDATE_RETURN}
- * @return true if the connection is valid
- */
- public boolean validate(Connection connection, int validateAction);
-}
+++ /dev/null
-/*
- * 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;
-
-public class XADataSource extends DataSource implements javax.sql.XADataSource {
-
- /**
- * Constructor for reflection only. A default set of pool properties will be created.
- */
- public XADataSource() {
- super();
- }
-
- /**
- * Constructs a DataSource object wrapping a connection
- * @param poolProperties
- */
- public XADataSource(PoolConfiguration poolProperties) {
- super(poolProperties);
- }
-
-}
+++ /dev/null
-/*
- * 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.JdbcInterceptor;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-
-/**
- * Abstraction interceptor. This component intercepts all calls to create some type of SQL statement.
- * By extending this class, one can intercept queries and update statements by overriding the {@link #createStatement(Object, Method, Object[], Object, long)}
- * method.
- * @author Filip Hanik
- * @version 1.0
- */
-public abstract class AbstractCreateStatementInterceptor extends JdbcInterceptor {
- protected static final String CREATE_STATEMENT = "createStatement";
- protected static final int CREATE_STATEMENT_IDX = 0;
- protected static final String PREPARE_STATEMENT = "prepareStatement";
- protected static final int PREPARE_STATEMENT_IDX = 1;
- protected static final String PREPARE_CALL = "prepareCall";
- protected static final int PREPARE_CALL_IDX = 2;
-
- protected static final String[] STATEMENT_TYPES = {CREATE_STATEMENT, PREPARE_STATEMENT, PREPARE_CALL};
- protected static final int STATEMENT_TYPE_COUNT = STATEMENT_TYPES.length;
-
- protected static final String EXECUTE = "execute";
- protected static final String EXECUTE_QUERY = "executeQuery";
- protected static final String EXECUTE_UPDATE = "executeUpdate";
- protected static final String EXECUTE_BATCH = "executeBatch";
-
- protected static final String[] EXECUTE_TYPES = {EXECUTE, EXECUTE_QUERY, EXECUTE_UPDATE, EXECUTE_BATCH};
-
- public AbstractCreateStatementInterceptor() {
- super();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (compare(CLOSE_VAL,method)) {
- closeInvoked();
- return super.invoke(proxy, method, args);
- } else {
- boolean process = false;
- process = isStatement(method, process);
- if (process) {
- long start = System.currentTimeMillis();
- Object statement = super.invoke(proxy,method,args);
- long delta = System.currentTimeMillis() - start;
- return createStatement(proxy,method,args,statement, delta);
- } else {
- return super.invoke(proxy,method,args);
- }
- }
- }
-
- /**
- * This method will be invoked after a successful statement creation. This method can choose to return a wrapper
- * around the statement or return the statement itself.
- * If this method returns a wrapper then it should return a wrapper object that implements one of the following interfaces.
- * {@link java.sql.Statement}, {@link java.sql.PreparedStatement} or {@link java.sql.CallableStatement}
- * @param proxy the actual proxy object
- * @param method the method that was called. It will be one of the methods defined in {@link #STATEMENT_TYPES}
- * @param args the arguments to the method
- * @param statement the statement that the underlying connection created
- * @return a {@link java.sql.Statement} object
- */
- public abstract Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time);
-
- /**
- * Method invoked when the operation {@link java.sql.Connection#close()} is invoked.
- */
- public abstract void closeInvoked();
-
- /**
- * Returns true if the method that is being invoked matches one of the statement types.
- *
- * @param method the method being invoked on the proxy
- * @param process boolean result used for recursion
- * @return returns true if the method name matched
- */
- protected boolean isStatement(Method method, boolean process){
- return process(STATEMENT_TYPES, method, process);
- }
-
- /**
- * Returns true if the method that is being invoked matches one of the execute types.
- *
- * @param method the method being invoked on the proxy
- * @param process boolean result used for recursion
- * @return returns true if the method name matched
- */
- protected boolean isExecute(Method method, boolean process){
- return process(EXECUTE_TYPES, method, process);
- }
-
- /*
- * Returns true if the method that is being invoked matches one of the method names passed in
- * @param names list of method names that we want to intercept
- * @param method the method being invoked on the proxy
- * @param process boolean result used for recursion
- * @return returns true if the method name matched
- */
- protected boolean process(String[] names, Method method, boolean process) {
- final String name = method.getName();
- for (int i=0; (!process) && i<names.length; i++) {
- process = compare(names[i],name);
- }
- return process;
- }
-
- /**
- * no-op for this interceptor. no state is stored.
- */
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- // NOOP
- }
-}
+++ /dev/null
-/*
- * 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.Constructor;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.sql.CallableStatement;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
-/**
- * Abstract class that wraps statements and intercepts query executions.
- * @author fhanik
- *
- */
-public abstract class AbstractQueryReport extends AbstractCreateStatementInterceptor {
- //logger
- private static final Log log = LogFactory.getLog(AbstractQueryReport.class);
-
- /**
- * The threshold in milliseconds. If the query is faster than this, we don't measure it
- */
- protected long threshold = 1000; //don't report queries less than this
-
- /**
- * the constructors that are used to create statement proxies
- */
- protected static final Constructor<?>[] constructors =
- new Constructor[AbstractCreateStatementInterceptor.STATEMENT_TYPE_COUNT];
-
-
- public AbstractQueryReport() {
- super();
- }
-
- /**
- * Invoked when prepareStatement has been called and completed.
- * @param sql - the string used to prepare the statement with
- * @param time - the time it took to invoke prepare
- */
- protected abstract void prepareStatement(String sql, long time);
-
- /**
- * Invoked when prepareCall has been called and completed.
- * @param query - the string used to prepare the statement with
- * @param time - the time it took to invoke prepare
- */
- protected abstract void prepareCall(String query, long time);
-
- /**
- * Invoked when a query execution, a call to execute/executeQuery or executeBatch failed.
- * @param query the query that was executed and failed
- * @param args the arguments to the execution
- * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
- * @param start the time the query execution started
- * @param t the exception that happened
- * @return - the SQL that was executed or the string "batch" if it was a batch execution
- */
- protected String reportFailedQuery(String query, Object[] args, final String name, long start, Throwable t) {
- //extract the query string
- String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query;
- //if we do batch execution, then we name the query 'batch'
- if (sql==null && compare(EXECUTE_BATCH,name)) {
- sql = "batch";
- }
- return sql;
- }
-
- /**
- * Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded and was within the timing threshold
- * @param query the query that was executed and failed
- * @param args the arguments to the execution
- * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
- * @param start the time the query execution started
- * @param delta the time the execution took
- * @return - the SQL that was executed or the string "batch" if it was a batch execution
- */
- protected String reportQuery(String query, Object[] args, final String name, long start, long delta) {
- //extract the query string
- String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query;
- //if we do batch execution, then we name the query 'batch'
- if (sql==null && compare(EXECUTE_BATCH,name)) {
- sql = "batch";
- }
- return sql;
- }
-
- /**
- * Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded and was exceeded the timing threshold
- * @param query the query that was executed and failed
- * @param args the arguments to the execution
- * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
- * @param start the time the query execution started
- * @param delta the time the execution took
- * @return - the SQL that was executed or the string "batch" if it was a batch execution
- */
- protected String reportSlowQuery(String query, Object[] args, final String name, long start, long delta) {
- //extract the query string
- String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query;
- //if we do batch execution, then we name the query 'batch'
- if (sql==null && compare(EXECUTE_BATCH,name)) {
- sql = "batch";
- }
- return sql;
- }
-
- /**
- * returns the query measure threshold.
- * This value is in milliseconds. If the query is faster than this threshold than it wont be accounted for
- * @return the threshhold in milliseconds
- */
- public long getThreshold() {
- return threshold;
- }
-
- /**
- * Sets the query measurement threshold. The value is in milliseconds.
- * If the query goes faster than this threshold it will not be recorded.
- * @param threshold set to -1 to record every query. Value is in milliseconds.
- */
- public void setThreshold(long threshold) {
- this.threshold = threshold;
- }
-
- /**
- * Creates a constructor for a proxy class, if one doesn't already exist
- * @param idx - the index of the constructor
- * @param clazz - the interface that the proxy will implement
- * @return - returns a constructor used to create new instances
- * @throws NoSuchMethodException
- */
- protected Constructor<?> getConstructor(int idx, Class<?> clazz) throws NoSuchMethodException {
- if (constructors[idx]==null) {
- Class<?> proxyClass = Proxy.getProxyClass(SlowQueryReport.class.getClassLoader(), new Class[] {clazz});
- constructors[idx] = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
- }
- return constructors[idx];
- }
-
- /**
- * Creates a statement interceptor to monitor query response times
- */
- @Override
- public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
- try {
- Object result = null;
- String name = method.getName();
- String sql = null;
- Constructor<?> constructor = null;
- if (compare(CREATE_STATEMENT,name)) {
- //createStatement
- constructor = getConstructor(CREATE_STATEMENT_IDX,Statement.class);
- }else if (compare(PREPARE_STATEMENT,name)) {
- //prepareStatement
- sql = (String)args[0];
- constructor = getConstructor(PREPARE_STATEMENT_IDX,PreparedStatement.class);
- if (sql!=null) {
- prepareStatement(sql, time);
- }
- }else if (compare(PREPARE_CALL,name)) {
- //prepareCall
- sql = (String)args[0];
- constructor = getConstructor(PREPARE_CALL_IDX,CallableStatement.class);
- prepareCall(sql,time);
- }else {
- //do nothing, might be a future unsupported method
- //so we better bail out and let the system continue
- return statement;
- }
- result = constructor.newInstance(new Object[] { new StatementProxy(statement,sql) });
- return result;
- }catch (Exception x) {
- log.warn("Unable to create statement proxy for slow query report.",x);
- }
- return statement;
- }
-
-
- /**
- * Class to measure query execute time
- * @author fhanik
- *
- */
- protected class StatementProxy implements InvocationHandler {
- protected boolean closed = false;
- protected Object delegate;
- protected final String query;
- public StatementProxy(Object parent, String query) {
- this.delegate = parent;
- this.query = query;
- }
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- //get the name of the method for comparison
- final String name = method.getName();
- //was close invoked?
- boolean close = compare(JdbcInterceptor.CLOSE_VAL,name);
- //allow close to be called multiple times
- if (close && closed) return null;
- //are we calling isClosed?
- if (compare(JdbcInterceptor.ISCLOSED_VAL,name)) return Boolean.valueOf(closed);
- //if we are calling anything else, bail out
- if (closed) throw new SQLException("Statement closed.");
- boolean process = false;
- //check to see if we are about to execute a query
- process = isExecute( method, process);
- //if we are executing, get the current time
- long start = (process)?System.currentTimeMillis():0;
- Object result = null;
- try {
- //execute the query
- result = method.invoke(delegate,args);
- }catch (Throwable t) {
- reportFailedQuery(query,args,name,start,t);
- if (t instanceof InvocationTargetException) {
- InvocationTargetException it = (InvocationTargetException)t;
- throw it.getCause()!=null?it.getCause():it;
- } else {
- throw t;
- }
- }
- //measure the time
- long delta = (process)?(System.currentTimeMillis()-start):Long.MIN_VALUE;
- //see if we meet the requirements to measure
- if (delta>threshold) {
- try {
- //report the slow query
- reportSlowQuery(query, args, name, start, delta);
- }catch (Exception t) {
- if (log.isWarnEnabled()) log.warn("Unable to process slow query",t);
- }
- } else if (process) {
- reportQuery(query, args, name, start, delta);
- }
- //perform close cleanup
- if (close) {
- closed=true;
- delegate = null;
- }
- return result;
- }
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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 java.sql.SQLException;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-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.PoolConfiguration;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-
-/**
- * Interceptor that keep track of connection state to avoid roundtrips to the database.
- * The {@link org.apache.tomcat.jdbc.pool.ConnectionPool} is optimized to do as little work as possible.
- * The pool itself doesn't remember settings like {@link java.sql.Connection#setAutoCommit(boolean)},
- * {@link java.sql.Connection#setReadOnly(boolean)}, {@link java.sql.Connection#setCatalog(String)} or
- * {@link java.sql.Connection#setTransactionIsolation(int)}. It relies on the application to remember how and when
- * these settings have been applied.
- * In the cases where the application code doesn't know or want to keep track of the state, this interceptor helps cache the
- * state, and it also avoids roundtrips to the database asking for it.
- * @author fhanik
- *
- */
-
-public class ConnectionState extends JdbcInterceptor {
- private static final Log log = LogFactory.getLog(ConnectionState.class);
-
- protected final String[] readState = {"getAutoCommit","getTransactionIsolation","isReadOnly","getCatalog"};
- protected final String[] writeState = {"setAutoCommit","setTransactionIsolation","setReadOnly","setCatalog"};
-
- protected Boolean autoCommit = null;
- protected Integer transactionIsolation = null;
- protected Boolean readOnly = null;
- protected String catalog = null;
-
-
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- if (parent==null || con==null) {
- //we are resetting, reset our defaults
- autoCommit = null;
- transactionIsolation = null;
- readOnly = null;
- catalog = null;
- return;
- }
- PoolConfiguration poolProperties = parent.getPoolProperties();
- if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) {
- try {
- if (transactionIsolation==null || transactionIsolation.intValue()!=poolProperties.getDefaultTransactionIsolation()) {
- con.getConnection().setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
- transactionIsolation = Integer.valueOf(poolProperties.getDefaultTransactionIsolation());
- }
- }catch (SQLException x) {
- transactionIsolation = null;
- log.error("Unable to reset transaction isolation state to connection.",x);
- }
- }
- if (poolProperties.getDefaultReadOnly()!=null) {
- try {
- if (readOnly==null || readOnly.booleanValue()!=poolProperties.getDefaultReadOnly().booleanValue()) {
- con.getConnection().setReadOnly(poolProperties.getDefaultReadOnly().booleanValue());
- readOnly = poolProperties.getDefaultReadOnly();
- }
- }catch (SQLException x) {
- readOnly = null;
- log.error("Unable to reset readonly state to connection.",x);
- }
- }
- if (poolProperties.getDefaultAutoCommit()!=null) {
- try {
- if (autoCommit==null || autoCommit.booleanValue()!=poolProperties.getDefaultAutoCommit().booleanValue()) {
- con.getConnection().setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue());
- autoCommit = poolProperties.getDefaultAutoCommit();
- }
- }catch (SQLException x) {
- autoCommit = null;
- log.error("Unable to reset autocommit state to connection.",x);
- }
- }
- if (poolProperties.getDefaultCatalog()!=null) {
- try {
- if (catalog==null || (!catalog.equals(poolProperties.getDefaultCatalog()))) {
- con.getConnection().setCatalog(poolProperties.getDefaultCatalog());
- catalog = poolProperties.getDefaultCatalog();
- }
- }catch (SQLException x) {
- catalog = null;
- log.error("Unable to reset default catalog state to connection.",x);
- }
- }
-
- }
-
- @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 = compare(name,readState[i]);
- if (read) index = i;
- }
- boolean write = false;
- for (int i=0; (!write) && (!read) && i<writeState.length; i++) {
- write = compare(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;}
- case 3:{result = catalog; 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;}
- case 3:{catalog = (String)(read?result:args[0]); break;}
- }
- }
- return result;
- }
-
-}
+++ /dev/null
-/*
- * 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.JdbcInterceptor;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-import org.apache.tomcat.jdbc.pool.ProxyConnection;
-
-/**
- * Class that resets the abandoned timer on any activity on the
- * Connection or any successful query executions.
- * This interceptor is useful for when you have a {@link org.apache.tomcat.jdbc.pool.PoolConfiguration#setRemoveAbandonedTimeout(int)}
- * that is fairly low, and you want to reset the abandoned time each time any operation on the connection is performed
- * This is useful for batch processing programs that use connections for extensive amount of times.
- * @author fhanik
- *
- */
-public class ResetAbandonedTimer extends AbstractQueryReport {
-
- public ResetAbandonedTimer() {
- // TODO Auto-generated constructor stub
- }
-
- public boolean resetTimer() {
- boolean result = false;
- JdbcInterceptor interceptor = this.getNext();
- while (interceptor!=null && result==false) {
- if (interceptor instanceof ProxyConnection) {
- PooledConnection con = ((ProxyConnection)interceptor).getConnection();
- if (con!=null) {
- con.setTimestamp(System.currentTimeMillis());
- result = true;
- } else {
- break;
- }
- }
- interceptor = interceptor.getNext();
- }
- return result;
- }
-
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // TODO Auto-generated method stub
- Object result = super.invoke(proxy, method, args);
- resetTimer();
- return result;
- }
-
- @Override
- protected void prepareCall(String query, long time) {
- resetTimer();
- }
-
- @Override
- protected void prepareStatement(String sql, long time) {
- resetTimer();
-
- }
-
- @Override
- public void closeInvoked() {
- resetTimer();
- }
-
- @Override
- protected String reportQuery(String query, Object[] args, String name,long start, long delta) {
- resetTimer();
- return super.reportQuery(query, args, name, start, delta);
- }
-
- @Override
- protected String reportSlowQuery(String query, Object[] args, String name,long start, long delta) {
- resetTimer();
- return super.reportSlowQuery(query, args, name, start, delta);
- }
-}
+++ /dev/null
-/*
- * 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.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
-
-/**
- * Slow query report interceptor. Tracks timing of query executions.
- * @author Filip Hanik
- * @version 1.0
- */
-public class SlowQueryReport extends AbstractQueryReport {
- //logger
- private static final Log log = LogFactory.getLog(SlowQueryReport.class);
-
- /**
- * we will be keeping track of query stats on a per pool basis
- */
- protected static ConcurrentHashMap<String,ConcurrentHashMap<String,QueryStats>> perPoolStats =
- new ConcurrentHashMap<String,ConcurrentHashMap<String,QueryStats>>();
- /**
- * the queries that are used for this interceptor.
- */
- protected ConcurrentHashMap<String,QueryStats> queries = null;
- /**
- * Maximum number of queries we will be storing
- */
- protected int maxQueries= 1000; //don't store more than this amount of queries
-
- /**
- * Returns the query stats for a given pool
- * @param poolname - the name of the pool we want to retrieve stats for
- * @return a hash map containing statistics for 0 to maxQueries
- */
- public static ConcurrentHashMap<String,QueryStats> getPoolStats(String poolname) {
- return perPoolStats.get(poolname);
- }
-
- /**
- * Creates a slow query report interceptor
- */
- public SlowQueryReport() {
- super();
- }
-
- public void setMaxQueries(int maxQueries) {
- this.maxQueries = maxQueries;
- }
-
-
- @Override
- protected String reportFailedQuery(String query, Object[] args, String name, long start, Throwable t) {
- String sql = super.reportFailedQuery(query, args, name, start, t);
- if (this.maxQueries > 0 ) {
- long now = System.currentTimeMillis();
- long delta = now - start;
- QueryStats qs = this.getQueryStats(sql);
- qs.failure(delta, now);
- }
- return sql;
- }
-
- @Override
- protected String reportSlowQuery(String query, Object[] args, String name, long start, long delta) {
- String sql = super.reportSlowQuery(query, args, name, start, delta);
- if (this.maxQueries > 0 ) {
- QueryStats qs = this.getQueryStats(sql);
- qs.add(delta, start);
- }
- return sql;
- }
-
- /**
- * invoked when the connection receives the close request
- * Not used for now.
- */
- @Override
- public void closeInvoked() {
- queries = null;
- }
-
- @Override
- public void prepareStatement(String sql, long time) {
- QueryStats qs = getQueryStats(sql);
- qs.prepare(time, System.currentTimeMillis());
- }
-
- @Override
- public void prepareCall(String sql, long time) {
- QueryStats qs = getQueryStats(sql);
- qs.prepare(time, System.currentTimeMillis());
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void poolStarted(ConnectionPool pool) {
- super.poolStarted(pool);
- //see if we already created a map for this pool
- queries = SlowQueryReport.perPoolStats.get(pool.getName());
- if (queries==null) {
- //create the map to hold our stats
- //however TODO we need to improve the eviction
- //selection
- queries = new ConcurrentHashMap<String,QueryStats>() {
-
- };
- if (perPoolStats.putIfAbsent(pool.getName(), queries)!=null) {
- //there already was one
- queries = SlowQueryReport.perPoolStats.get(pool.getName());
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void poolClosed(ConnectionPool pool) {
- perPoolStats.remove(pool.getName());
- super.poolClosed(pool);
- }
-
- protected QueryStats getQueryStats(String sql) {
- ConcurrentHashMap<String,QueryStats> queries = SlowQueryReport.this.queries;
- if (queries==null) return null;
- QueryStats qs = queries.get(sql);
- if (qs == null) {
- qs = new QueryStats(sql);
- if (queries.putIfAbsent(sql,qs)!=null) {
- qs = queries.get(sql);
- } else {
- //we added a new element, see if we need to remove the oldest
- if (queries.size() > maxQueries) {
- removeOldest(queries);
- }
- }
- }
- return qs;
- }
-
- /**
- * TODO - implement a better algorithm
- * @param queries
- */
- protected void removeOldest(ConcurrentHashMap<String,QueryStats> queries) {
- Iterator<String> it = queries.keySet().iterator();
- while (queries.size()>maxQueries && it.hasNext()) {
- String sql = it.next();
- it.remove();
- if (log.isDebugEnabled()) log.debug("Removing slow query, capacity reached:"+sql);
- }
- }
-
-
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- super.reset(parent, con);
- if (parent!=null)
- queries = SlowQueryReport.perPoolStats.get(parent.getName());
- }
-
-
- @Override
- public void setProperties(Map<String, InterceptorProperty> properties) {
- super.setProperties(properties);
- final String threshold = "threshold";
- final String maxqueries= "maxQueries";
- InterceptorProperty p1 = properties.get(threshold);
- InterceptorProperty p2 = properties.get(maxqueries);
- if (p1!=null) {
- setThreshold(Long.parseLong(p1.getValue()));
- }
- if (p2!=null) {
- setMaxQueries(Integer.parseInt(p2.getValue()));
- }
- }
-
-
- /**
- *
- * @author fhanik
- *
- */
- public static class QueryStats {
- static final String[] FIELD_NAMES = new String[] {
- "query",
- "nrOfInvocations",
- "maxInvocationTime",
- "maxInvocationDate",
- "minInvocationTime",
- "minInvocationDate",
- "totalInvocationTime",
- "failures",
- "prepareCount",
- "prepareTime",
- "lastInvocation"
- };
-
- static final String[] FIELD_DESCRIPTIONS = new String[] {
- "The SQL query",
- "The number of query invocations, a call to executeXXX",
- "The longest time for this query in milliseconds",
- "The time and date for when the longest query took place",
- "The shortest time for this query in milliseconds",
- "The time and date for when the shortest query took place",
- "The total amount of milliseconds spent executing this query",
- "The number of failures for this query",
- "The number of times this query was prepared (prepareStatement/prepareCall)",
- "The total number of milliseconds spent preparing this query",
- "The date and time of the last invocation"
- };
-
- static final OpenType[] FIELD_TYPES = new OpenType[] {
- SimpleType.STRING,
- SimpleType.INTEGER,
- SimpleType.LONG,
- SimpleType.LONG,
- SimpleType.LONG,
- SimpleType.LONG,
- SimpleType.LONG,
- SimpleType.LONG,
- SimpleType.INTEGER,
- SimpleType.LONG,
- SimpleType.LONG
- };
-
- private final String query;
- private int nrOfInvocations;
- private long maxInvocationTime = Long.MIN_VALUE;
- private long maxInvocationDate;
- private long minInvocationTime = Long.MAX_VALUE;
- private long minInvocationDate;
- private long totalInvocationTime;
- private long failures;
- private int prepareCount;
- private long prepareTime;
- private volatile long lastInvocation = 0;
-
- public static String[] getFieldNames() {
- return FIELD_NAMES;
- }
-
- public static String[] getFieldDescriptions() {
- return FIELD_DESCRIPTIONS;
- }
-
- public static OpenType[] getFieldTypes() {
- return FIELD_TYPES;
- }
-
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder("QueryStats[query:");
- buf.append(query);
- buf.append(", nrOfInvocations:");
- buf.append(nrOfInvocations);
- buf.append(", maxInvocationTime:");
- buf.append(maxInvocationTime);
- buf.append(", maxInvocationDate:");
- buf.append(new java.util.Date(maxInvocationDate).toGMTString());
- buf.append(", minInvocationTime:");
- buf.append(minInvocationTime);
- buf.append(", minInvocationDate:");
- buf.append(new java.util.Date(minInvocationDate).toGMTString());
- buf.append(", totalInvocationTime:");
- buf.append(totalInvocationTime);
- buf.append(", averageInvocationTime:");
- buf.append((float)totalInvocationTime / (float)nrOfInvocations);
- buf.append(", failures:");
- buf.append(failures);
- buf.append(", prepareCount:");
- buf.append(prepareCount);
- buf.append(", prepareTime:");
- buf.append(prepareTime);
- buf.append("]");
- return buf.toString();
- }
-
- public CompositeDataSupport getCompositeData(final CompositeType type) throws OpenDataException{
- Object[] values = new Object[] {
- query,
- Integer.valueOf(nrOfInvocations),
- Long.valueOf(maxInvocationTime),
- Long.valueOf(maxInvocationDate),
- Long.valueOf(minInvocationTime),
- Long.valueOf(minInvocationDate),
- Long.valueOf(totalInvocationTime),
- Long.valueOf(failures),
- Integer.valueOf(prepareCount),
- Long.valueOf(prepareTime),
- Long.valueOf(lastInvocation)
- };
- return new CompositeDataSupport(type,FIELD_NAMES,values);
- }
-
- public QueryStats(String query) {
- this.query = query;
- }
-
- public void prepare(long invocationTime, long now) {
- prepareCount++;
- prepareTime+=invocationTime;
-
- }
-
- public void add(long invocationTime, long now) {
- //not thread safe, but don't sacrifice performance for this kind of stuff
- maxInvocationTime = Math.max(invocationTime, maxInvocationTime);
- if (maxInvocationTime == invocationTime) {
- maxInvocationDate = now;
- }
- minInvocationTime = Math.min(invocationTime, minInvocationTime);
- if (minInvocationTime==invocationTime) {
- minInvocationDate = now;
- }
- nrOfInvocations++;
- totalInvocationTime+=invocationTime;
- lastInvocation = now;
- }
-
- public void failure(long invocationTime, long now) {
- add(invocationTime,now);
- failures++;
-
- }
-
- public String getQuery() {
- return query;
- }
-
- public int getNrOfInvocations() {
- return nrOfInvocations;
- }
-
- public long getMaxInvocationTime() {
- return maxInvocationTime;
- }
-
- public long getMaxInvocationDate() {
- return maxInvocationDate;
- }
-
- public long getMinInvocationTime() {
- return minInvocationTime;
- }
-
- public long getMinInvocationDate() {
- return minInvocationDate;
- }
-
- public long getTotalInvocationTime() {
- return totalInvocationTime;
- }
-
- @Override
- public int hashCode() {
- return query.hashCode();
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof QueryStats) {
- QueryStats qs = (QueryStats)other;
- return qs.query.equals(this.query);
- }
- return false;
- }
-
- public boolean isOlderThan(QueryStats other) {
- return this.lastInvocation < other.lastInvocation;
- }
- }
-
-
-}
+++ /dev/null
-/*
- * 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.management.ManagementFactory;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanException;
-import javax.management.MBeanNotificationInfo;
-import javax.management.MBeanRegistrationException;
-import javax.management.MalformedObjectNameException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.Notification;
-import javax.management.NotificationBroadcasterSupport;
-import javax.management.NotificationEmitter;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import javax.management.RuntimeOperationsException;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenDataException;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
-/**
- * Publishes data to JMX and provides notifications
- * when failures happen.
- * @author fhanik
- *
- */
-public class SlowQueryReportJmx extends SlowQueryReport implements NotificationEmitter, SlowQueryReportJmxMBean{
- public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY";
- public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY";
-
- protected static CompositeType SLOW_QUERY_TYPE;
-
- private static final Log log = LogFactory.getLog(SlowQueryReportJmx.class);
-
-
- protected static ConcurrentHashMap<String,SlowQueryReportJmxMBean> mbeans =
- new ConcurrentHashMap<String,SlowQueryReportJmxMBean>();
-
-
- //==============================JMX STUFF========================
- protected volatile NotificationBroadcasterSupport notifier = new NotificationBroadcasterSupport();
-
- public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException {
- notifier.addNotificationListener(listener, filter, handback);
- }
-
-
- public MBeanNotificationInfo[] getNotificationInfo() {
- return notifier.getNotificationInfo();
- }
-
- public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
- notifier.removeNotificationListener(listener);
-
- }
-
- public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
- notifier.removeNotificationListener(listener, filter, handback);
-
- }
-
-
- //==============================JMX STUFF========================
-
- protected String poolName = null;
-
- protected static AtomicLong notifySequence = new AtomicLong(0);
-
- protected boolean notifyPool = true;
-
- protected ConnectionPool pool = null;
-
- protected static CompositeType getCompositeType() {
- if (SLOW_QUERY_TYPE==null) {
- try {
- SLOW_QUERY_TYPE = new CompositeType(
- SlowQueryReportJmx.class.getName(),
- "Composite data type for query statistics",
- QueryStats.getFieldNames(),
- QueryStats.getFieldDescriptions(),
- QueryStats.getFieldTypes());
- }catch (OpenDataException x) {
- log.warn("Unable to initialize composite data type for JMX stats and notifications.",x);
- }
- }
- return SLOW_QUERY_TYPE;
- }
-
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- // TODO Auto-generated method stub
- super.reset(parent, con);
- if (parent!=null) {
- poolName = parent.getName();
- pool = parent;
- registerJmx();
- }
- }
-
-
- @Override
- public void poolClosed(ConnectionPool pool) {
- this.poolName = pool.getName();
- deregisterJmx();
- super.poolClosed(pool);
- }
-
- @Override
- public void poolStarted(ConnectionPool pool) {
- this.pool = pool;
- super.poolStarted(pool);
- this.poolName = pool.getName();
- }
-
- @Override
- protected String reportFailedQuery(String query, Object[] args, String name, long start, Throwable t) {
- query = super.reportFailedQuery(query, args, name, start, t);
- notifyJmx(query,FAILED_QUERY_NOTIFICATION);
- return query;
- }
-
- protected void notifyJmx(String query, String type) {
- try {
- long sequence = notifySequence.incrementAndGet();
-
- if (isNotifyPool()) {
- if (this.pool!=null && this.pool.getJmxPool()!=null) {
- this.pool.getJmxPool().notify(type, query);
- }
- } else {
- if (notifier!=null) {
- Notification notification =
- new Notification(type,
- this,
- sequence,
- System.currentTimeMillis(),
- query);
-
- notifier.sendNotification(notification);
- }
- }
- } catch (RuntimeOperationsException e) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to send failed query notification.",e);
- }
- }
- }
-
- @Override
- protected String reportSlowQuery(String query, Object[] args, String name, long start, long delta) {
- query = super.reportSlowQuery(query, args, name, start, delta);
- notifyJmx(query,SLOW_QUERY_NOTIFICATION);
- return query;
- }
-
- /**
- * JMX operation - return the names of all the pools
- * @return - all the names of pools that we have stored data for
- */
- public String[] getPoolNames() {
- Set<String> keys = perPoolStats.keySet();
- return keys.toArray(new String[0]);
- }
-
- /**
- * JMX operation - return the name of the pool
- * @return the name of the pool, unique within the JVM
- */
- public String getPoolName() {
- return poolName;
- }
-
-
- public boolean isNotifyPool() {
- return notifyPool;
- }
-
- public void setNotifyPool(boolean notifyPool) {
- this.notifyPool = notifyPool;
- }
-
- /**
- * JMX operation - remove all stats for this connection pool
- */
- public void resetStats() {
- ConcurrentHashMap<String,QueryStats> queries = perPoolStats.get(poolName);
- if (queries!=null) {
- Iterator<String> it = queries.keySet().iterator();
- while (it.hasNext()) it.remove();
- }
- }
-
- /**
- * JMX operation - returns all the queries we have collected.
- * @return - the slow query report as composite data.
- */
- public CompositeData[] getSlowQueriesCD() throws OpenDataException {
- CompositeDataSupport[] result = null;
- ConcurrentHashMap<String,QueryStats> queries = perPoolStats.get(poolName);
- if (queries!=null) {
- Set<Map.Entry<String,QueryStats>> stats = queries.entrySet();
- if (stats!=null) {
- result = new CompositeDataSupport[stats.size()];
- Iterator<Map.Entry<String,QueryStats>> it = stats.iterator();
- int pos = 0;
- while (it.hasNext()) {
- Map.Entry<String,QueryStats> entry = it.next();
- QueryStats qs = entry.getValue();
- result[pos++] = qs.getCompositeData(getCompositeType());
- }
- }
- }
- return result;
- }
-
- protected void deregisterJmx() {
- try {
- if (mbeans.remove(poolName)!=null) {
- ObjectName oname = getObjectName(getClass(),poolName);
- ManagementFactory.getPlatformMBeanServer().unregisterMBean(oname);
- }
- } catch (MBeanRegistrationException e) {
- log.debug("Jmx deregistration failed.",e);
- } catch (InstanceNotFoundException e) {
- log.debug("Jmx deregistration failed.",e);
- } catch (MalformedObjectNameException e) {
- log.warn("Jmx deregistration failed.",e);
- } catch (RuntimeOperationsException e) {
- log.warn("Jmx deregistration failed.",e);
- }
-
- }
-
-
- public static ObjectName getObjectName(Class<?> clazz, String poolName) throws MalformedObjectNameException {
- ObjectName oname = new ObjectName(ConnectionPool.POOL_JMX_TYPE_PREFIX+clazz.getName()+",name=" + poolName);
- return oname;
- }
-
- protected void registerJmx() {
- try {
- //only if we notify the pool itself
- if (isNotifyPool()) {
-
- } else if (getCompositeType()!=null) {
- ObjectName oname = getObjectName(getClass(),poolName);
- if (mbeans.putIfAbsent(poolName, this)==null) {
- ManagementFactory.getPlatformMBeanServer().registerMBean(this, oname);
- }
- } else {
- log.warn(SlowQueryReport.class.getName()+ "- No JMX support, composite type was not found.");
- }
- } catch (MalformedObjectNameException e) {
- log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
- } catch (RuntimeOperationsException e) {
- log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
- } catch (MBeanException e) {
- log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
- } catch (InstanceAlreadyExistsException e) {
- log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
- } catch (NotCompliantMBeanException e) {
- log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
- }
- }
-
- @Override
- public void setProperties(Map<String, InterceptorProperty> properties) {
- super.setProperties(properties);
- final String threshold = "notifyPool";
- InterceptorProperty p1 = properties.get(threshold);
- if (p1!=null) {
- this.setNotifyPool(Boolean.parseBoolean(p1.getValue()));
- }
- }
-
-
-}
+++ /dev/null
-/* 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 javax.management.openmbean.CompositeData;
-import javax.management.openmbean.OpenDataException;
-
-public interface SlowQueryReportJmxMBean {
- public CompositeData[] getSlowQueriesCD() throws OpenDataException;
-}
+++ /dev/null
-/* 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.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.sql.Statement;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
-
-public class StatementCache extends StatementDecoratorInterceptor {
- protected static final String[] ALL_TYPES = new String[] {PREPARE_STATEMENT,PREPARE_CALL};
- protected static final String[] CALLABLE_TYPE = new String[] {PREPARE_CALL};
- protected static final String[] PREPARED_TYPE = new String[] {PREPARE_STATEMENT};
- protected static final String[] NO_TYPE = new String[] {};
-
- protected static final String STATEMENT_CACHE_ATTR = StatementCache.class.getName() + ".cache";
-
- /*begin properties for the statement cache*/
- private boolean cachePrepared = true;
- private boolean cacheCallable = false;
- private int maxCacheSize = 50;
- private PooledConnection pcon;
- private String[] types;
-
-
- public boolean isCachePrepared() {
- return cachePrepared;
- }
-
- public boolean isCacheCallable() {
- return cacheCallable;
- }
-
- public int getMaxCacheSize() {
- return maxCacheSize;
- }
-
- public String[] getTypes() {
- return types;
- }
-
- public AtomicInteger getCacheSize() {
- return cacheSize;
- }
-
- @Override
- public void setProperties(Map<String, InterceptorProperty> properties) {
- super.setProperties(properties);
- InterceptorProperty p = properties.get("prepared");
- if (p!=null) cachePrepared = p.getValueAsBoolean(cachePrepared);
- p = properties.get("callable");
- if (p!=null) cacheCallable = p.getValueAsBoolean(cacheCallable);
- p = properties.get("max");
- if (p!=null) maxCacheSize = p.getValueAsInt(maxCacheSize);
- if (cachePrepared && cacheCallable) {
- this.types = ALL_TYPES;
- } else if (cachePrepared) {
- this.types = PREPARED_TYPE;
- } else if (cacheCallable) {
- this.types = CALLABLE_TYPE;
- } else {
- this.types = NO_TYPE;
- }
-
- }
- /*end properties for the statement cache*/
-
- /*begin the cache size*/
- private static ConcurrentHashMap<ConnectionPool,AtomicInteger> cacheSizeMap =
- new ConcurrentHashMap<ConnectionPool,AtomicInteger>();
-
- private AtomicInteger cacheSize;
-
- @Override
- public void poolStarted(ConnectionPool pool) {
- cacheSizeMap.putIfAbsent(pool, new AtomicInteger(0));
- super.poolStarted(pool);
- }
-
- @Override
- public void poolClosed(ConnectionPool pool) {
- cacheSizeMap.remove(pool);
- super.poolClosed(pool);
- }
- /*end the cache size*/
-
- /*begin the actual statement cache*/
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- super.reset(parent, con);
- if (parent==null) {
- cacheSize = null;
- this.pcon = null;
- } else {
- cacheSize = cacheSizeMap.get(parent);
- this.pcon = con;
- if (!pcon.getAttributes().containsKey(STATEMENT_CACHE_ATTR)) {
- ConcurrentHashMap<String,CachedStatement> cache = new ConcurrentHashMap<String, CachedStatement>();
- pcon.getAttributes().put(STATEMENT_CACHE_ATTR,cache);
- }
- }
- }
-
- @Override
- public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {
- ConcurrentHashMap<String,CachedStatement> statements =
- (ConcurrentHashMap<String,CachedStatement>)con.getAttributes().get(STATEMENT_CACHE_ATTR);
-
- if (statements!=null) {
- for (Map.Entry<String, CachedStatement> p : statements.entrySet()) {
- closeStatement(p.getValue());
- }
- statements.clear();
- }
-
- super.disconnected(parent, con, finalizing);
- }
-
- public void closeStatement(CachedStatement st) {
- if (st==null) return;
- st.forceClose();
- }
-
- @Override
- protected Object createDecorator(Object proxy, Method method, Object[] args,
- Object statement, Constructor<?> constructor, String sql)
- throws InstantiationException, IllegalAccessException, InvocationTargetException {
- boolean process = process(this.types, method, false);
- if (process) {
- Object result = null;
- CachedStatement statementProxy = new CachedStatement((Statement)statement,sql);
- result = constructor.newInstance(new Object[] { statementProxy });
- statementProxy.setActualProxy(result);
- statementProxy.setConnection(proxy);
- statementProxy.setConstructor(constructor);
- return result;
- } else {
- return super.createDecorator(proxy, method, args, statement, constructor, sql);
- }
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- boolean process = process(this.types, method, false);
- if (process && args.length>0 && args[0] instanceof String) {
- CachedStatement statement = isCached((String)args[0]);
- if (statement!=null) {
- //remove it from the cache since it is used
- removeStatement(statement);
- return statement.getActualProxy();
- } else {
- return super.invoke(proxy, method, args);
- }
- } else {
- return super.invoke(proxy,method,args);
- }
- }
-
- public CachedStatement isCached(String sql) {
- ConcurrentHashMap<String,CachedStatement> cache =
- (ConcurrentHashMap<String,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
- return cache.get(sql);
- }
-
- public boolean cacheStatement(CachedStatement proxy) {
- ConcurrentHashMap<String,CachedStatement> cache =
- (ConcurrentHashMap<String,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
- if (proxy.getSql()==null) {
- return false;
- } else if (cache.containsKey(proxy.getSql())) {
- return false;
- } else if (cacheSize.get()>=maxCacheSize) {
- return false;
- } else if (cacheSize.incrementAndGet()>maxCacheSize) {
- cacheSize.decrementAndGet();
- return false;
- } else {
- //cache the statement
- cache.put(proxy.getSql(), proxy);
- return true;
- }
- }
-
- public boolean removeStatement(CachedStatement proxy) {
- ConcurrentHashMap<String,CachedStatement> cache =
- (ConcurrentHashMap<String,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
- if (cache.remove(proxy.getSql()) != null) {
- cacheSize.decrementAndGet();
- return true;
- } else {
- return false;
- }
- }
- /*end the actual statement cache*/
-
-
- protected class CachedStatement extends StatementDecoratorInterceptor.StatementProxy<Statement> {
- boolean cached = false;
- public CachedStatement(Statement parent, String sql) {
- super(parent, sql);
- }
-
- @Override
- public void closeInvoked() {
- //should we cache it
- boolean shouldClose = true;
- if (cacheSize.get() < maxCacheSize) {
- //cache a proxy so that we don't reuse the facade
- CachedStatement proxy = new CachedStatement(getDelegate(),getSql());
- try {
- //create a new facade
- Object actualProxy = getConstructor().newInstance(new Object[] { proxy });
- proxy.setActualProxy(actualProxy);
- proxy.setConnection(getConnection());
- proxy.setConstructor(getConstructor());
- if (cacheStatement(proxy)) {
- proxy.cached = true;
- shouldClose = false;
- }
- } catch (Exception x) {
- removeStatement(proxy);
- }
- }
- closed = true;
- delegate = null;
- if (shouldClose) {
- super.closeInvoked();
- }
-
- }
-
- public void forceClose() {
- removeStatement(this);
- super.closeInvoked();
- }
-
- }
-
-}
-
-
+++ /dev/null
-/*
- * 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.Constructor;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.sql.CallableStatement;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor;
-
-/**
- * Implementation of <b>JdbcInterceptor</b> that proxies resultSets and statements.
- * @author Guillermo Fernandes
- */
-public class StatementDecoratorInterceptor extends AbstractCreateStatementInterceptor {
-
- private static final Log logger = LogFactory.getLog(StatementDecoratorInterceptor.class);
-
- private static final String[] EXECUTE_QUERY_TYPES = { "executeQuery" };
-
- /**
- * the constructors that are used to create statement proxies
- */
- protected static final Constructor<?>[] constructors = new Constructor[AbstractCreateStatementInterceptor.STATEMENT_TYPE_COUNT];
-
- /**
- * the constructor to create the resultSet proxies
- */
- protected static Constructor<?> resultSetConstructor = null;
-
- @Override
- public void closeInvoked() {
- // nothing to do
- }
-
- /**
- * Creates a constructor for a proxy class, if one doesn't already exist
- *
- * @param idx
- * - the index of the constructor
- * @param clazz
- * - the interface that the proxy will implement
- * @return - returns a constructor used to create new instances
- * @throws NoSuchMethodException
- */
- protected Constructor<?> getConstructor(int idx, Class<?> clazz) throws NoSuchMethodException {
- if (constructors[idx] == null) {
- Class<?> proxyClass = Proxy.getProxyClass(StatementDecoratorInterceptor.class.getClassLoader(),
- new Class[] { clazz });
- constructors[idx] = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
- }
- return constructors[idx];
- }
-
- protected Constructor<?> getResultSetConstructor() throws NoSuchMethodException {
- if (resultSetConstructor == null) {
- Class<?> proxyClass = Proxy.getProxyClass(StatementDecoratorInterceptor.class.getClassLoader(),
- new Class[] { ResultSet.class });
- resultSetConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
- }
- return resultSetConstructor;
- }
-
- /**
- * Creates a statement interceptor to monitor query response times
- */
- @Override
- public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
- try {
- String name = method.getName();
- Constructor<?> constructor = null;
- String sql = null;
- if (compare(CREATE_STATEMENT, name)) {
- // createStatement
- constructor = getConstructor(CREATE_STATEMENT_IDX, Statement.class);
- } else if (compare(PREPARE_STATEMENT, name)) {
- // prepareStatement
- constructor = getConstructor(PREPARE_STATEMENT_IDX, PreparedStatement.class);
- sql = (String)args[0];
- } else if (compare(PREPARE_CALL, name)) {
- // prepareCall
- constructor = getConstructor(PREPARE_CALL_IDX, CallableStatement.class);
- sql = (String)args[0];
- } else {
- // do nothing, might be a future unsupported method
- // so we better bail out and let the system continue
- return statement;
- }
- return createDecorator(proxy, method, args, statement, constructor, sql);
- } catch (Exception x) {
- logger.warn("Unable to create statement proxy for slow query report.", x);
- }
- return statement;
- }
-
- protected Object createDecorator(Object proxy, Method method, Object[] args,
- Object statement, Constructor<?> constructor, String sql)
- throws InstantiationException, IllegalAccessException, InvocationTargetException {
- Object result = null;
- StatementProxy statementProxy = new StatementProxy<Statement>((Statement)statement,sql);
- result = constructor.newInstance(new Object[] { statementProxy });
- statementProxy.setActualProxy(result);
- statementProxy.setConnection(proxy);
- statementProxy.setConnection(constructor);
- return result;
- }
-
- protected boolean isExecuteQuery(String methodName) {
- return EXECUTE_QUERY_TYPES[0].equals(methodName);
- }
-
- protected boolean isExecuteQuery(Method method) {
- return isExecuteQuery(method.getName());
- }
-
- /**
- * Class to measure query execute time
- *
- * @author fhanik
- *
- */
- protected class StatementProxy<T extends java.sql.Statement> implements InvocationHandler {
-
- protected boolean closed = false;
- protected T delegate;
- private Object actualProxy;
- private Object connection;
- private String sql;
- private Constructor constructor;
-
- public StatementProxy(T delegate, String sql) {
- this.delegate = delegate;
- this.sql = sql;
- }
- public T getDelegate() {
- return this.delegate;
- }
-
- public String getSql() {
- return sql;
- }
-
- public void setConnection(Object proxy) {
- this.connection = proxy;
- }
- public Object getConnection() {
- return this.connection;
- }
-
- public void setActualProxy(Object proxy){
- this.actualProxy = proxy;
- }
- public Object getActualProxy() {
- return this.actualProxy;
- }
-
-
- public Constructor getConstructor() {
- return constructor;
- }
- public void setConstructor(Constructor constructor) {
- this.constructor = constructor;
- }
- public void closeInvoked() {
- if (getDelegate()!=null) {
- try {
- getDelegate().close();
- }catch (SQLException ignore) {
- }
- }
- closed = true;
- delegate = null;
- }
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (compare(TOSTRING_VAL,method)) {
- return toString();
- }
- // was close invoked?
- boolean close = compare(CLOSE_VAL, method);
- // allow close to be called multiple times
- if (close && closed)
- return null;
- // are we calling isClosed?
- if (compare(ISCLOSED_VAL, method))
- return Boolean.valueOf(closed);
- // if we are calling anything else, bail out
- if (closed)
- throw new SQLException("Statement closed.");
- if (compare(GETCONNECTION_VAL,method)){
- return connection;
- }
- boolean process = isExecuteQuery(method);
- // check to see if we are about to execute a query
- // if we are executing, get the current time
- Object result = null;
- try {
- // perform close cleanup
- if (close) {
- closeInvoked();
- } else {
- // execute the query
- result = method.invoke(delegate, args);
- }
- } catch (Throwable t) {
- if (t instanceof InvocationTargetException) {
- InvocationTargetException it = (InvocationTargetException) t;
- throw it.getCause() != null ? it.getCause() : it;
- } else {
- throw t;
- }
- }
- if (process){
- Constructor<?> cons = getResultSetConstructor();
- result = cons.newInstance(new Object[]{new ResultSetProxy(actualProxy, result)});
- }
- return result;
- }
-
- public String toString() {
- StringBuffer buf = new StringBuffer(StatementProxy.class.getName());
- buf.append("[Proxy=");
- buf.append(System.identityHashCode(this));
- buf.append("; Sql=");
- buf.append(getSql());
- buf.append("; Delegate=");
- buf.append(getDelegate());
- buf.append("; Connection=");
- buf.append(getConnection());
- buf.append("]");
- return buf.toString();
- }
- }
-
- protected class ResultSetProxy implements InvocationHandler {
-
- private Object st;
- private Object delegate;
-
- public ResultSetProxy(Object st, Object delegate) {
- this.st = st;
- this.delegate = delegate;
- }
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.getName().equals("getStatement")) {
- return this.st;
- } else {
- return method.invoke(this.delegate, args);
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.ref.WeakReference;
-import java.lang.reflect.Method;
-import java.sql.Statement;
-import java.util.ArrayList;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-/**
- * Keeps track of statements associated with a connection and invokes close upon {@link java.sql.Connection#close()}
- * Useful for applications that dont close the associated statements after being done with a connection.
- * @author fhanik
- *
- */
-public class StatementFinalizer extends AbstractCreateStatementInterceptor {
- private static final Log log = LogFactory.getLog(StatementFinalizer.class);
-
- protected ArrayList<WeakReference<Statement>> statements = new ArrayList<WeakReference<Statement>>();
-
- @Override
- public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
- // TODO Auto-generated method stub
- try {
- if (statement instanceof Statement)
- statements.add(new WeakReference<Statement>((Statement)statement));
- }catch (ClassCastException x) {
- //ignore this one
- }
- return statement;
- }
-
- @Override
- public void closeInvoked() {
- while (statements.size()>0) {
- WeakReference<Statement> ws = statements.remove(0);
- Statement st = ws.get();
- if (st!=null) {
- try {
- st.close();
- } catch (Exception ignore) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to closed statement upon connection close.",ignore);
- }
- }
- }
- }
- }
-
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- statements.clear();
- super.reset(parent, con);
- }
-
-
-}
+++ /dev/null
-<?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.
--->
-<mbeans-descriptors>
-
- <mbean description="Reports " domain="tomcat.jdbc" group="jdbc-pool" name="SlowQueryReportJmx"
- type="org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx">
-
- <attribute description="The name of the connection pool this Jmx bean is representing" name="poolName" type="java.lang.String" writeable="false"/>
- <attribute description="List of all registered connections pools" name="poolNames" type="[java.lang.String;" writeable="false"/>
- <attribute description="All the recorded query stats. " name="slowQueriesCD" type="[javax.management.openmbean.CompositeData;" writeable="false"/>
- <operation description="Clears all the query stats" impact="ACTION" name="resetStats" returnType="void"/>
-
- <notification description="Notification sent out by the slow query report when a query exceeds the threshhold" name="slow-query">
- <notification-type>Slow query</notification-type>
- </notification>
-
- <notification description="Notification sent out by the slow query report when a query fails execution" name="failed-query">
- <notification-type>Failed query execution</notification-type>
- </notification>
- </mbean>
-</mbeans-descriptors>
\ No newline at end of file
+++ /dev/null
-/* 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 java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.management.MBeanNotificationInfo;
-import javax.management.Notification;
-import javax.management.NotificationBroadcasterSupport;
-import javax.management.NotificationListener;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jdbc.pool.PoolConfiguration;
-import org.apache.tomcat.jdbc.pool.PoolUtilities;
-import org.apache.tomcat.jdbc.pool.Validator;
-import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
-
-public class ConnectionPool extends NotificationBroadcasterSupport implements ConnectionPoolMBean {
- /**
- * logger
- */
- private static final Log log = LogFactory.getLog(ConnectionPool.class);
-
- /**
- * the connection pool
- */
- protected org.apache.tomcat.jdbc.pool.ConnectionPool pool = null;
- /**
- * sequence for JMX notifications
- */
- protected AtomicInteger sequence = new AtomicInteger(0);
-
- /**
- * Listeners that are local and interested in our notifications, no need for JMX
- */
- protected ConcurrentLinkedQueue<NotificationListener> listeners = new ConcurrentLinkedQueue<NotificationListener>();
-
- public ConnectionPool(org.apache.tomcat.jdbc.pool.ConnectionPool pool) {
- super();
- this.pool = pool;
- }
-
- public org.apache.tomcat.jdbc.pool.ConnectionPool getPool() {
- return pool;
- }
-
- public PoolConfiguration getPoolProperties() {
- return pool.getPoolProperties();
- }
-
- //=================================================================
- // NOTIFICATION INFO
- //=================================================================
- public static final String NOTIFY_INIT = "INIT FAILED";
- public static final String NOTIFY_CONNECT = "CONNECTION FAILED";
- public static final String NOTIFY_ABANDON = "CONNECTION ABANDONED";
- public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY";
- public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY";
- public static final String SUSPECT_ABANDONED_NOTIFICATION = "SUSPECT CONNETION ABANDONED";
-
- @Override
- public MBeanNotificationInfo[] getNotificationInfo() {
- MBeanNotificationInfo[] pres = super.getNotificationInfo();
- MBeanNotificationInfo[] loc = getDefaultNotificationInfo();
- MBeanNotificationInfo[] aug = new MBeanNotificationInfo[pres.length + loc.length];
- if (pres.length>0) System.arraycopy(pres, 0, aug, 0, pres.length);
- if (loc.length >0) System.arraycopy(loc, 0, aug, pres.length, loc.length);
- return aug;
- }
-
- public static MBeanNotificationInfo[] getDefaultNotificationInfo() {
- String[] types = new String[] {NOTIFY_INIT, NOTIFY_CONNECT, NOTIFY_ABANDON, SLOW_QUERY_NOTIFICATION, FAILED_QUERY_NOTIFICATION, SUSPECT_ABANDONED_NOTIFICATION};
- String name = Notification.class.getName();
- String description = "A connection pool error condition was met.";
- MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
- return new MBeanNotificationInfo[] {info};
- }
-
- /**
- * Return true if the notification was sent successfully, false otherwise.
- * @param type
- * @param message
- * @return true if the notification succeeded
- */
- public boolean notify(final String type, String message) {
- try {
- Notification n = new Notification(
- type,
- this,
- sequence.incrementAndGet(),
- System.currentTimeMillis(),
- "["+type+"] "+message);
- sendNotification(n);
- for (NotificationListener listener : listeners) {
- listener.handleNotification(n,this);
- }
- return true;
- }catch (Exception x) {
- if (log.isDebugEnabled()) {
- log.debug("Notify failed. Type="+type+"; Message="+message,x);
- }
- return false;
- }
-
- }
-
- public void addListener(NotificationListener list) {
- listeners.add(list);
- }
-
- public boolean removeListener(NotificationListener list) {
- return listeners.remove(list);
- }
-
- //=================================================================
- // POOL STATS
- //=================================================================
-
- public int getSize() {
- return pool.getSize();
- }
-
- public int getIdle() {
- return pool.getIdle();
- }
-
- public int getActive() {
- return pool.getActive();
- }
-
- public int getNumIdle() {
- return getIdle();
- }
-
- public int getNumActive() {
- return getActive();
- }
-
- public int getWaitCount() {
- return pool.getWaitCount();
- }
-
- //=================================================================
- // POOL OPERATIONS
- //=================================================================
- public void checkIdle() {
- pool.checkIdle();
- }
-
- public void checkAbandoned() {
- pool.checkAbandoned();
- }
-
- public void testIdle() {
- pool.testAllIdle();
- }
- //=================================================================
- // POOL PROPERTIES
- //=================================================================
- //=========================================================
- // PROPERTIES / CONFIGURATION
- //=========================================================
-
-
- public String getConnectionProperties() {
- return getPoolProperties().getConnectionProperties();
- }
-
- public Properties getDbProperties() {
- return PoolUtilities.cloneWithoutPassword(getPoolProperties().getDbProperties());
- }
-
- public String getDefaultCatalog() {
- return getPoolProperties().getDefaultCatalog();
- }
-
- public int getDefaultTransactionIsolation() {
- return getPoolProperties().getDefaultTransactionIsolation();
- }
-
- public String getDriverClassName() {
- return getPoolProperties().getDriverClassName();
- }
-
-
- public int getInitialSize() {
- return getPoolProperties().getInitialSize();
- }
-
- public String getInitSQL() {
- return getPoolProperties().getInitSQL();
- }
-
- public String getJdbcInterceptors() {
- return getPoolProperties().getJdbcInterceptors();
- }
-
- public int getMaxActive() {
- return getPoolProperties().getMaxActive();
- }
-
- public int getMaxIdle() {
- return getPoolProperties().getMaxIdle();
- }
-
- public int getMaxWait() {
- return getPoolProperties().getMaxWait();
- }
-
- public int getMinEvictableIdleTimeMillis() {
- return getPoolProperties().getMinEvictableIdleTimeMillis();
- }
-
- public int getMinIdle() {
- return getPoolProperties().getMinIdle();
- }
-
- public long getMaxAge() {
- return getPoolProperties().getMaxAge();
- }
-
- public String getName() {
- return this.getPoolName();
- }
-
- public int getNumTestsPerEvictionRun() {
- return getPoolProperties().getNumTestsPerEvictionRun();
- }
-
- /**
- * @return DOES NOT RETURN THE PASSWORD, IT WOULD SHOW UP IN JMX
- */
- public String getPassword() {
- return "Password not available as DataSource/JMX operation.";
- }
-
- public int getRemoveAbandonedTimeout() {
- return getPoolProperties().getRemoveAbandonedTimeout();
- }
-
-
- public int getTimeBetweenEvictionRunsMillis() {
- return getPoolProperties().getTimeBetweenEvictionRunsMillis();
- }
-
- public String getUrl() {
- return getPoolProperties().getUrl();
- }
-
- public String getUsername() {
- return getPoolProperties().getUsername();
- }
-
- public long getValidationInterval() {
- return getPoolProperties().getValidationInterval();
- }
-
- public String getValidationQuery() {
- return getPoolProperties().getValidationQuery();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public String getValidatorClassName() {
- return getPoolProperties().getValidatorClassName();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public Validator getValidator() {
- return getPoolProperties().getValidator();
- }
-
- public boolean isAccessToUnderlyingConnectionAllowed() {
- return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
- }
-
- public Boolean isDefaultAutoCommit() {
- return getPoolProperties().isDefaultAutoCommit();
- }
-
- public Boolean isDefaultReadOnly() {
- return getPoolProperties().isDefaultReadOnly();
- }
-
- public boolean isLogAbandoned() {
- return getPoolProperties().isLogAbandoned();
- }
-
- public boolean isPoolSweeperEnabled() {
- return getPoolProperties().isPoolSweeperEnabled();
- }
-
- public boolean isRemoveAbandoned() {
- return getPoolProperties().isRemoveAbandoned();
- }
-
- public int getAbandonWhenPercentageFull() {
- return getPoolProperties().getAbandonWhenPercentageFull();
- }
-
- public boolean isTestOnBorrow() {
- return getPoolProperties().isTestOnBorrow();
- }
-
- public boolean isTestOnConnect() {
- return getPoolProperties().isTestOnConnect();
- }
-
- public boolean isTestOnReturn() {
- return getPoolProperties().isTestOnReturn();
- }
-
- public boolean isTestWhileIdle() {
- return getPoolProperties().isTestWhileIdle();
- }
-
-
- public Boolean getDefaultAutoCommit() {
- return getPoolProperties().getDefaultAutoCommit();
- }
-
- public Boolean getDefaultReadOnly() {
- return getPoolProperties().getDefaultReadOnly();
- }
-
- public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
- return getPoolProperties().getJdbcInterceptorsAsArray();
- }
-
- public boolean getUseLock() {
- return getPoolProperties().getUseLock();
- }
-
- public boolean isFairQueue() {
- return getPoolProperties().isFairQueue();
- }
-
- public boolean isJmxEnabled() {
- return getPoolProperties().isJmxEnabled();
- }
-
- public boolean isUseEquals() {
- return getPoolProperties().isUseEquals();
- }
-
- public void setAbandonWhenPercentageFull(int percentage) {
- getPoolProperties().setAbandonWhenPercentageFull(percentage);
- }
-
- public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
- getPoolProperties().setAccessToUnderlyingConnectionAllowed(accessToUnderlyingConnectionAllowed);
- }
-
- public void setDbProperties(Properties dbProperties) {
- getPoolProperties().setDbProperties(dbProperties);
- }
-
- public void setDefaultReadOnly(Boolean defaultReadOnly) {
- getPoolProperties().setDefaultReadOnly(defaultReadOnly);
- }
-
- public void setMaxAge(long maxAge) {
- getPoolProperties().setMaxAge(maxAge);
- }
-
- public void setName(String name) {
- getPoolProperties().setName(name);
- }
-
- public String getPoolName() {
- return getPoolProperties().getName();
- }
-
-
- public void setConnectionProperties(String connectionProperties) {
- getPoolProperties().setConnectionProperties(connectionProperties);
-
- }
-
- public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
- getPoolProperties().setDefaultAutoCommit(defaultAutoCommit);
- }
-
- public void setDefaultCatalog(String defaultCatalog) {
- getPoolProperties().setDefaultCatalog(defaultCatalog);
- }
-
- public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
- getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
- }
-
- public void setDriverClassName(String driverClassName) {
- getPoolProperties().setDriverClassName(driverClassName);
- }
-
-
- public void setFairQueue(boolean fairQueue) {
- getPoolProperties().setFairQueue(fairQueue);
- }
-
-
- public void setInitialSize(int initialSize) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setInitSQL(String initSQL) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setJdbcInterceptors(String jdbcInterceptors) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setJmxEnabled(boolean jmxEnabled) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setLogAbandoned(boolean logAbandoned) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setMaxActive(int maxActive) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setMaxIdle(int maxIdle) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setMaxWait(int maxWait) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setMinIdle(int minIdle) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setPassword(String password) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setRemoveAbandoned(boolean removeAbandoned) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setTestOnBorrow(boolean testOnBorrow) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setTestOnConnect(boolean testOnConnect) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setTestOnReturn(boolean testOnReturn) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setTestWhileIdle(boolean testWhileIdle) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setUrl(String url) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setUseEquals(boolean useEquals) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setUseLock(boolean useLock) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setUsername(String username) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setValidationInterval(long validationInterval) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setValidationQuery(String validationQuery) {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setValidatorClassName(String className) {
- getPoolProperties().setValidatorClassName(className);
- }
-
- /**
- * {@inheritDoc}
- */
-
- public int getSuspectTimeout() {
- return getPoolProperties().getSuspectTimeout();
- }
-
- /**
- * {@inheritDoc}
- */
-
- public void setSuspectTimeout(int seconds) {
- //no op
- }
-
- /**
- * {@inheritDoc}
- */
- public void setDataSource(Object ds) {
- getPoolProperties().setDataSource(ds);
- }
-
- /**
- * {@inheritDoc}
- */
- public Object getDataSource() {
- return getPoolProperties().getDataSource();
- }
-
-
- /**
- * {@inheritDoc}
- */
- public void setDataSourceJNDI(String jndiDS) {
- //noop
- }
-
- /**
- * {@inheritDoc}
- */
- public String getDataSourceJNDI() {
- return getPoolProperties().getDataSourceJNDI();
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isAlternateUsernameAllowed() {
- return getPoolProperties().isAlternateUsernameAllowed();
- }
-
- /**
- * {@inheritDoc}
- */
- public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
- //noop
- }
-
-}
+++ /dev/null
-/* 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 org.apache.tomcat.jdbc.pool.PoolConfiguration;
-
-public interface ConnectionPoolMBean extends PoolConfiguration {
-
- //=================================================================
- // POOL STATS
- //=================================================================
-
- public int getSize();
-
- public int getIdle();
-
- public int getActive();
-
- public boolean isPoolSweeperEnabled();
-
- public int getNumIdle();
-
- public int getNumActive();
-
- public int getWaitCount();
-
- //=================================================================
- // POOL OPERATIONS
- //=================================================================
- public void checkIdle();
-
- public void checkAbandoned();
-
- public void testIdle();
-
- //=================================================================
- // POOL NOTIFICATIONS
- //=================================================================
-
-
-}
+++ /dev/null
-<?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.
--->
-<mbeans-descriptors>
-
- <mbean name="TomcatJDBCPool"
- description="Provides per diagnostic metrics and notifications for JDBC operations"
- domain="tomcat"
- group="jdbc"
- type="org.apache.tomcat.jdbc.pool.DataSource">
-
- <attribute name="className"
- description="Fully qualified class name of the managed object"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="size"
- description="The number of established connections in the pool, idle and in use"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="idle"
- description="The number of established connections in the pool that are idle"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="numIdle"
- description="Same as the idle attribute"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="active"
- description="The number of established connections in the pool that are in use"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="numActive"
- description="Same as the active attribute"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="poolSweeperEnabled"
- description="Returns true if the pool has a background thread running"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="url"
- description="The JDBC url for this connection pool"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="driverClassName"
- description="The JDBC driver class for this connection pool"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="defaultAutoCommit"
- description="The JDBC auto commit setting for new connections"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="defaultReadOnly"
- description="The JDBC read only setting for new connections"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="defaultTransactionIsolation"
- description="The JDBC transaction isolation setting for new connections"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="connectionProperties"
- description="The connection properties that will be set for new connections. Format of the string will be [propertyName=property;]*"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="defaultCatalog"
- description="The JDBC transaction isolation setting for new connections"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="initialSize"
- description="The number of connections opened at pool startup"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="maxActive"
- description="The maximum number of open connections"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="maxIdle"
- description="The max number of idle connections"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="minIdle"
- description="The minimum number of open connections"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="maxWait"
- description="The time to wait in milliseconds before a SQLException is thrown when a connection is requested"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="validationQuery"
- description="The query to run during validation"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="testOnBorrow"
- description="True if validation happens when a connection is requested"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="testOnReturn"
- description="True if validation happens when a connection is returned"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="testWhileIdle"
- description="True if validation happens when a connection is not in use (idle)"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="timeBetweenEvictionRunsMillis"
- description="Sleep time for background thread in between pool checks"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="numTestsPerEvictionRun"
- description="Not in use"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="minEvictableIdleTimeMillis"
- description="Minimum amount of time a connection stays idle before it is evicted"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="accessToUnderlyingConnectionAllowed"
- description="Returns true if one can retrieve the actual JDBC connection"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="removeAbandoned"
- description="Returns true if connection in use can be timed out"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="removeAbandonedTimeout"
- description="Timeout in seconds for connections in use"
- type="java.lang.Integer"
- writeable="false"/>
-
- <attribute name="logAbandoned"
- description="If true, stack trace will be recorded and printed out for timed out connection"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="loginTimeout"
- description="Not in use"
- type="java.lang.Integer"
- writeable="false"/>
-
-
- <attribute name="name"
- description="The name of the connection pool, will be used in the ObjectName of the actual pool"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="password"
- description="For security purposes,this doesn't return anything"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="username"
- description="The username used to open connections"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="validationInterval"
- description="If larger than zero than validation will only occur after the interval milliseconds has passed"
- type="java.lang.Long"
- writeable="false"/>
-
- <attribute name="initSQL"
- description="A SQL executed once per connection, when it is established"
- type="java.lang.String"
- writeable="false"/>
-
- <attribute name="testOnConnect"
- description="Validate connection after connection has been established"
- type="java.lang.Boolean"
- is="true"
- writeable="false"/>
-
- <attribute name="jdbcInterceptors"
- description="The interceptors configured for this pool"
- type="java.lang.String"
- writeable="false"/>
-
- <operation name="checkIdle"
- description="forces a check of idle connections"
- impact="ACTION"
- returnType="void" />
-
- <operation name="checkAbandoned"
- description="forces a check of abandoned connections"
- impact="ACTION"
- returnType="void" />
-
- <operation name="testIdle"
- description="forces a validation of abandoned connections"
- impact="ACTION"
- returnType="void" />
- </mbean>
-
-</mbeans-descriptors>
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+ <modelVersion>4.0.0</modelVersion>\r
+ <groupId>org.apache.tomcat</groupId>\r
+ <artifactId>jdbc-pool</artifactId>\r
+ <version>1.2-SNAPSHOT</version>\r
+ <packaging>jar</packaging>\r
+\r
+ <name>jdbc-pool</name>\r
+ <url>http://people.apache.org/~fhanik/jdbc-pool/</url>\r
+ \r
+ <properties>\r
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\r
+ </properties>\r
+ \r
+ <mailingLists>\r
+ <mailingList>\r
+ <name>Development List</name>\r
+ <subscribe>dev-subscribe@tomcat.apache.org</subscribe>\r
+ <unsubscribe>dev-unsubscribe@tomcat.apache.org</unsubscribe>\r
+ <post>dev@tomcat.apache.org</post>\r
+ </mailingList>\r
+ <mailingList>\r
+ <name>Users List</name>\r
+ <subscribe>users-subscribe@tomcat.apache.org</subscribe>\r
+ <unsubscribe>users-unsubscribe@tomcat.apache.org</unsubscribe>\r
+ <post>users@tomcat.apache.org</post>\r
+ </mailingList>\r
+ </mailingLists>\r
+ \r
+ <distributionManagement>\r
+ <snapshotRepository>\r
+ <id>apache.snapshots.https</id>\r
+ <name>Apache Development Snapshot Repository</name>\r
+ <url>https://repository.apache.org/content/repositories/snapshots</url>\r
+ <uniqueVersion>false</uniqueVersion>\r
+ </snapshotRepository>\r
+ </distributionManagement> \r
+\r
+ <scm>\r
+ <connection>scm:svn:https://svn.apache.org/repos/asf/tomcat/trunk/modules/jdbc-pool</connection>\r
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/tomcat/trunk/modules/jdbc-pool</developerConnection>\r
+ <url>http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool</url>\r
+ </scm> \r
+\r
+ <dependencies>\r
+ <dependency>\r
+ <groupId>org.apache.tomcat</groupId>\r
+ <artifactId>juli</artifactId>\r
+ <version>6.0.32</version>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>junit</groupId>\r
+ <artifactId>junit</artifactId>\r
+ <version>3.8.1</version>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.apache.tomcat</groupId>\r
+ <artifactId>dbcp</artifactId>\r
+ <version>6.0.32</version>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>com.h2database</groupId>\r
+ <artifactId>h2</artifactId>\r
+ <version>1.3.152</version>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ </dependencies>\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-compiler-plugin</artifactId>\r
+ <configuration>\r
+ <source>1.6</source>\r
+ <target>1.6</target>\r
+ <optimize>true</optimize>\r
+ <debug>true</debug>\r
+ <showDeprecation>true</showDeprecation>\r
+ <showWarnings>true</showWarnings>\r
+ </configuration>\r
+ </plugin>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-gpg-plugin</artifactId>\r
+ <version>1.2</version>\r
+ <executions>\r
+ <execution>\r
+ <id>sign-artifacts</id>\r
+ <phase>verify</phase>\r
+ <goals>\r
+ <goal>sign</goal>\r
+ </goals>\r
+ </execution>\r
+ </executions>\r
+ </plugin>\r
+ <plugin>\r
+ <groupId>org.apache.maven.plugins</groupId>\r
+ <artifactId>maven-eclipse-plugin</artifactId>\r
+ <version>2.5.1</version>\r
+ <configuration>\r
+ <downloadSources>true</downloadSources>\r
+ <downloadJavadocs>false</downloadJavadocs>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins> \r
+ </build> \r
+</project>\r
--- /dev/null
+/*
+ * 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.naming;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+/**
+ * Simple way of configuring generic resources by using reflection.
+ * Example usage:
+ * <pre><code>
+ * <Resource factory="org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory"
+ * name="jdbc/test"
+ * type="org.apache.derby.jdbc.ClientXADataSource"
+ * databaseName="sample"
+ * createDatabase="create"
+ * serverName="localhost"
+ * port="1527"/>
+ * </code></pre>
+ *
+ */
+public class GenericNamingResourcesFactory implements ObjectFactory {
+ private static final Log log = LogFactory.getLog(GenericNamingResourcesFactory.class);
+
+ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
+ if ((obj == null) || !(obj instanceof Reference)) {
+ return null;
+ }
+ Reference ref = (Reference) obj;
+ Enumeration<RefAddr> refs = ref.getAll();
+
+ String type = ref.getClassName();
+ Object o = Class.forName(type).newInstance();
+
+ while (refs.hasMoreElements()) {
+ RefAddr addr = refs.nextElement();
+ String param = addr.getType();
+ String value = null;
+ if (addr.getContent()!=null) {
+ value = addr.getContent().toString();
+ }
+ if (setProperty(o, param, value,false)) {
+
+ } else {
+ log.debug("Property not configured["+param+"]. No setter found on["+o+"].");
+ }
+ }
+ return o;
+ }
+
+ public static boolean setProperty(Object o, String name, String value,boolean invokeSetProperty) {
+ if (log.isDebugEnabled())
+ log.debug("IntrospectionUtils: setProperty(" +
+ o.getClass() + " " + name + "=" + value + ")");
+
+ String setter = "set" + capitalize(name);
+
+ try {
+ Method methods[] = o.getClass().getMethods();
+ Method setPropertyMethodVoid = null;
+ Method setPropertyMethodBool = null;
+
+ // First, the ideal case - a setFoo( String ) method
+ for (int i = 0; i < methods.length; i++) {
+ Class<?> paramT[] = methods[i].getParameterTypes();
+ if (setter.equals(methods[i].getName()) && paramT.length == 1
+ && "java.lang.String".equals(paramT[0].getName())) {
+
+ methods[i].invoke(o, new Object[] { value });
+ return true;
+ }
+ }
+
+ // Try a setFoo ( int ) or ( boolean )
+ for (int i = 0; i < methods.length; i++) {
+ boolean ok = true;
+ if (setter.equals(methods[i].getName())
+ && methods[i].getParameterTypes().length == 1) {
+
+ // match - find the type and invoke it
+ Class<?> paramType = methods[i].getParameterTypes()[0];
+ Object params[] = new Object[1];
+
+ // Try a setFoo ( int )
+ if ("java.lang.Integer".equals(paramType.getName())
+ || "int".equals(paramType.getName())) {
+ try {
+ params[0] = new Integer(value);
+ } catch (NumberFormatException ex) {
+ ok = false;
+ }
+ // Try a setFoo ( long )
+ }else if ("java.lang.Long".equals(paramType.getName())
+ || "long".equals(paramType.getName())) {
+ try {
+ params[0] = new Long(value);
+ } catch (NumberFormatException ex) {
+ ok = false;
+ }
+
+ // Try a setFoo ( boolean )
+ } else if ("java.lang.Boolean".equals(paramType.getName())
+ || "boolean".equals(paramType.getName())) {
+ params[0] = new Boolean(value);
+
+ // Try a setFoo ( InetAddress )
+ } else if ("java.net.InetAddress".equals(paramType
+ .getName())) {
+ try {
+ params[0] = InetAddress.getByName(value);
+ } catch (UnknownHostException exc) {
+ if (log.isDebugEnabled())
+ log.debug("IntrospectionUtils: Unable to resolve host name:" + value);
+ ok = false;
+ }
+
+ // Unknown type
+ } else {
+ if (log.isDebugEnabled())
+ log.debug("IntrospectionUtils: Unknown type " +
+ paramType.getName());
+ }
+
+ if (ok) {
+ methods[i].invoke(o, params);
+ return true;
+ }
+ }
+
+ // save "setProperty" for later
+ if ("setProperty".equals(methods[i].getName())) {
+ if (methods[i].getReturnType()==Boolean.TYPE){
+ setPropertyMethodBool = methods[i];
+ }else {
+ setPropertyMethodVoid = methods[i];
+ }
+
+ }
+ }
+
+ // Ok, no setXXX found, try a setProperty("name", "value")
+ if (setPropertyMethodBool != null || setPropertyMethodVoid != null) {
+ Object params[] = new Object[2];
+ params[0] = name;
+ params[1] = value;
+ if (setPropertyMethodBool != null) {
+ try {
+ return (Boolean) setPropertyMethodBool.invoke(o, params);
+ }catch (IllegalArgumentException biae) {
+ //the boolean method had the wrong
+ //parameter types. lets try the other
+ if (setPropertyMethodVoid!=null) {
+ setPropertyMethodVoid.invoke(o, params);
+ return true;
+ }else {
+ throw biae;
+ }
+ }
+ } else {
+ setPropertyMethodVoid.invoke(o, params);
+ return true;
+ }
+ }
+
+ } catch (IllegalArgumentException ex2) {
+ log.warn("IAE " + o + " " + name + " " + value, ex2);
+ } catch (SecurityException ex1) {
+ if (log.isDebugEnabled())
+ log.debug("IntrospectionUtils: SecurityException for " +
+ o.getClass() + " " + name + "=" + value + ")", ex1);
+ } catch (IllegalAccessException iae) {
+ if (log.isDebugEnabled())
+ log.debug("IntrospectionUtils: IllegalAccessException for " +
+ o.getClass() + " " + name + "=" + value + ")", iae);
+ } catch (InvocationTargetException ie) {
+ if (log.isDebugEnabled())
+ log.debug("IntrospectionUtils: InvocationTargetException for " +
+ o.getClass() + " " + name + "=" + value + ")", ie);
+ }
+ return false;
+ }
+
+ public static String capitalize(String name) {
+ if (name == null || name.length() == 0) {
+ return name;
+ }
+ char chars[] = name.toCharArray();
+ chars[0] = Character.toUpperCase(chars[0]);
+ return new String(chars);
+ }
+
+}
--- /dev/null
+/*
+ * 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.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.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Implementation of simple connection pool.
+ * The ConnectionPool uses a {@link PoolProperties} object for storing all the meta information about the connection pool.
+ * As the underlying implementation, the connection pool uses {@link java.util.concurrent.BlockingQueue} to store active and idle connections.
+ * A custom implementation of a fair {@link FairBlockingQueue} blocking queue is provided with the connection pool itself.
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public class ConnectionPool {
+ /**
+ * Prefix type for JMX registration
+ */
+ public static final String POOL_JMX_TYPE_PREFIX = "tomcat.jdbc:type=";
+
+ /**
+ * Logger
+ */
+ private static final Log log = LogFactory.getLog(ConnectionPool.class);
+
+ //===============================================================================
+ // INSTANCE/QUICK ACCESS VARIABLE
+ //===============================================================================
+ /**
+ * Carries the size of the pool, instead of relying on a queue implementation
+ * that usually iterates over to get an exact count
+ */
+ private AtomicInteger size = new AtomicInteger(0);
+
+ /**
+ * All the information about the connection pool
+ * These are the properties the pool got instantiated with
+ */
+ private PoolConfiguration poolProperties;
+
+ /**
+ * Contains all the connections that are in use
+ * TODO - this shouldn't be a blocking queue, simply a list to hold our objects
+ */
+ private BlockingQueue<PooledConnection> busy;
+
+ /**
+ * Contains all the idle connections
+ */
+ private BlockingQueue<PooledConnection> idle;
+
+ /**
+ * The thread that is responsible for checking abandoned and idle threads
+ */
+ private volatile PoolCleaner poolCleaner;
+
+ /**
+ * Pool closed flag
+ */
+ private volatile boolean closed = false;
+
+ /**
+ * Since newProxyInstance performs the same operation, over and over
+ * again, it is much more optimized if we simply store the constructor ourselves.
+ */
+ private Constructor<?> proxyClassConstructor;
+
+ /**
+ * Executor service used to cancel Futures
+ */
+ private ThreadPoolExecutor cancellator = new ThreadPoolExecutor(0,1,1000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
+
+ /**
+ * reference to the JMX mbean
+ */
+ protected org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool = null;
+
+ /**
+ * counter to track how many threads are waiting for a connection
+ */
+ private AtomicInteger waitcount = new AtomicInteger(0);
+
+ //===============================================================================
+ // PUBLIC METHODS
+ //===============================================================================
+
+ /**
+ * Instantiate a connection pool. This will create connections if initialSize is larger than 0.
+ * The {@link PoolProperties} should not be reused for another connection pool.
+ * @param prop PoolProperties - all the properties for this connection pool
+ * @throws SQLException
+ */
+ public ConnectionPool(PoolConfiguration prop) throws SQLException {
+ //setup quick access variables and pools
+ init(prop);
+ }
+
+
+ /**
+ * Retrieves a Connection future. If a connection is not available, one can block using future.get()
+ * until a connection has become available.
+ * If a connection is not retrieved, the Future must be cancelled in order for the connection to be returned
+ * to the pool.
+ * @return a Future containing a reference to the connection or the future connection
+ * @throws SQLException
+ */
+ public Future<Connection> getConnectionAsync() throws SQLException {
+ try {
+ PooledConnection pc = borrowConnection(0, null, null);
+ if (pc!=null) {
+ return new ConnectionFuture(pc);
+ }
+ }catch (SQLException x) {
+ if (x.getMessage().indexOf("NoWait")<0) {
+ throw x;
+ }
+ }
+ //we can only retrieve a future if the underlying queue supports it.
+ if (idle instanceof FairBlockingQueue<?>) {
+ Future<PooledConnection> pcf = ((FairBlockingQueue<PooledConnection>)idle).pollAsync();
+ return new ConnectionFuture(pcf);
+ } else if (idle instanceof MultiLockFairBlockingQueue<?>) {
+ Future<PooledConnection> pcf = ((MultiLockFairBlockingQueue<PooledConnection>)idle).pollAsync();
+ return new ConnectionFuture(pcf);
+ } else {
+ throw new SQLException("Connection pool is misconfigured, doesn't support async retrieval. Set the 'fair' property to 'true'");
+ }
+ }
+
+ /**
+ * Borrows a connection from the pool. If a connection is available (in the idle queue) or the pool has not reached
+ * {@link PoolProperties#maxActive maxActive} connections a connection is returned immediately.
+ * If no connection is available, the pool will attempt to fetch a connection for {@link PoolProperties#maxWait maxWait} milliseconds.
+ * @return Connection - a java.sql.Connection/javax.sql.PooledConnection reflection proxy, wrapping the underlying object.
+ * @throws SQLException - if the wait times out or a failure occurs creating a connection
+ */
+ public Connection getConnection() throws SQLException {
+ //check out a connection
+ PooledConnection con = borrowConnection(-1,null,null);
+ return setupConnection(con);
+ }
+
+
+ /**
+ * Borrows a connection from the pool. If a connection is available (in the
+ * idle queue) or the pool has not reached {@link PoolProperties#maxActive
+ * maxActive} connections a connection is returned immediately. If no
+ * connection is available, the pool will attempt to fetch a connection for
+ * {@link PoolProperties#maxWait maxWait} milliseconds.
+ *
+ * @return Connection - a java.sql.Connection/javax.sql.PooledConnection
+ * reflection proxy, wrapping the underlying object.
+ * @throws SQLException
+ * - if the wait times out or a failure occurs creating a
+ * connection
+ */
+ public Connection getConnection(String username, String password) throws SQLException {
+ // check out a connection
+ PooledConnection con = borrowConnection(-1, username, password);
+ return setupConnection(con);
+ }
+
+ /**
+ * Returns the name of this pool
+ * @return String - the name of the pool
+ */
+ public String getName() {
+ return getPoolProperties().getPoolName();
+ }
+
+ /**
+ * Return the number of threads waiting for a connection
+ * @return number of threads waiting for a connection
+ */
+ public int getWaitCount() {
+ return waitcount.get();
+ }
+
+ /**
+ * Returns the pool properties associated with this connection pool
+ * @return PoolProperties
+ *
+ */
+ public PoolConfiguration getPoolProperties() {
+ return this.poolProperties;
+ }
+
+ /**
+ * Returns the total size of this pool, this includes both busy and idle connections
+ * @return int - number of established connections to the database
+ */
+ public int getSize() {
+ return size.get();
+ }
+
+ /**
+ * Returns the number of connections that are in use
+ * @return int - number of established connections that are being used by the application
+ */
+ public int getActive() {
+ return busy.size();
+ }
+
+ /**
+ * Returns the number of idle connections
+ * @return int - number of established connections not being used
+ */
+ 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;
+ }
+
+ //===============================================================================
+ // PROTECTED METHODS
+ //===============================================================================
+
+
+ /**
+ * configures a pooled connection as a proxy.
+ * This Proxy implements {@link java.sql.Connection} and {@link javax.sql.PooledConnection} interfaces.
+ * All calls on {@link java.sql.Connection} methods will be propagated down to the actual JDBC connection except for the
+ * {@link java.sql.Connection#close()} method.
+ * @param con a {@link PooledConnection} to wrap in a Proxy
+ * @return a {@link java.sql.Connection} object wrapping a pooled connection.
+ * @throws SQLException if an interceptor can't be configured, if the proxy can't be instantiated
+ */
+ protected Connection setupConnection(PooledConnection con) throws SQLException {
+ //fetch previously cached interceptor proxy - one per connection
+ JdbcInterceptor handler = con.getHandler();
+ if (handler==null) {
+ //build the proxy handler
+ handler = new ProxyConnection(this,con,getPoolProperties().isUseEquals());
+ //set up the interceptor chain
+ PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
+ for (int i=proxies.length-1; i>=0; i--) {
+ try {
+ //create a new instance
+ JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
+ //configure properties
+ interceptor.setProperties(proxies[i].getProperties());
+ //setup the chain
+ interceptor.setNext(handler);
+ //call reset
+ interceptor.reset(this, con);
+ //configure the last one to be held by the connection
+ 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 {
+ getProxyConstructor(con.getXAConnection() != null);
+ //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) {
+ SQLException s = new SQLException();
+ s.initCause(x);
+ throw s;
+ }
+
+ }
+
+ /**
+ * Creates and caches a {@link java.lang.reflect.Constructor} used to instantiate the proxy object.
+ * We cache this, since the creation of a constructor is fairly slow.
+ * @return constructor used to instantiate the wrapper object
+ * @throws NoSuchMethodException
+ */
+ public Constructor<?> getProxyConstructor(boolean xa) throws NoSuchMethodException {
+ //cache the constructor
+ if (proxyClassConstructor == null ) {
+ Class<?> proxyClass = xa ?
+ Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class, javax.sql.XAConnection.class}) :
+ Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class});
+ proxyClassConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+ }
+ return proxyClassConstructor;
+ }
+
+ /**
+ * 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.interrupted();
+ }
+ if (pool.size()==0 && force && pool!=busy) pool = busy;
+ }
+ if (this.getPoolProperties().isJmxEnabled()) this.jmxPool = null;
+ PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
+ for (int i=0; i<proxies.length; i++) {
+ try {
+ proxies[i].getInterceptorClass().newInstance().poolClosed(this);
+ }catch (Exception x) {
+ log.debug("Unable to inform interceptor of pool closure.",x);
+ }
+ }
+ } //closePool
+
+
+ /**
+ * Initialize the connection pool - called from the constructor
+ * @param properties PoolProperties - properties used to initialize the pool with
+ * @throws SQLException if initialization fails
+ */
+ protected void init(PoolConfiguration properties) throws SQLException {
+ poolProperties = properties;
+ //make space for 10 extra in case we flow over a bit
+ busy = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),false);
+ //busy = new FairBlockingQueue<PooledConnection>();
+ //make space for 10 extra in case we flow over a bit
+ if (properties.isFairQueue()) {
+ idle = new FairBlockingQueue<PooledConnection>();
+ //idle = new MultiLockFairBlockingQueue<PooledConnection>();
+ } else {
+ idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),properties.isFairQueue());
+ }
+
+ //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
+
+ //make sure the pool is properly configured
+ if (properties.getMaxActive()<1) {
+ log.warn("maxActive is smaller than 1, setting maxActive to: "+PoolProperties.DEFAULT_MAX_ACTIVE);
+ properties.setMaxActive(PoolProperties.DEFAULT_MAX_ACTIVE);
+ }
+ 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());
+ }
+
+ //create JMX MBean
+ if (this.getPoolProperties().isJmxEnabled()) createMBean();
+
+ //Parse and create an initial set of interceptors. Letting them know the pool has started.
+ //These interceptors will not get any connection.
+ PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
+ for (int i=0; i<proxies.length; i++) {
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Creating interceptor instance of class:"+proxies[i].getInterceptorClass());
+ }
+ proxies[i].getInterceptorClass().newInstance().poolStarted(this);
+ }catch (Exception x) {
+ log.error("Unable to inform interceptor of pool start.",x);
+ if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));
+ close(true);
+ SQLException ex = new SQLException();
+ ex.initCause(x);
+ throw ex;
+ }
+ }
+
+ //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(0, null, null); //don't wait, should be no contention
+ } //for
+
+ } catch (SQLException x) {
+ if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(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){/*NOOP*/}
+ } //end if
+ } //for
+ } //catch
+
+ closed = false;
+ }
+
+
+//===============================================================================
+// CONNECTION POOLING IMPL LOGIC
+//===============================================================================
+
+ /**
+ * 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();
+ String trace = con.getStackTrace();
+ if (getPoolProperties().isLogAbandoned()) {
+ log.warn("Connection has been abandoned " + con + ":" + trace);
+ }
+ if (jmxPool!=null) {
+ jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_ABANDON, trace);
+ }
+ //release the connection
+ release(con);
+ } finally {
+ con.unlock();
+ }
+ }
+
+ /**
+ * 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 suspect(PooledConnection con) {
+ if (con == null)
+ return;
+ if (con.isSuspect())
+ return;
+ try {
+ con.lock();
+ String trace = con.getStackTrace();
+ if (getPoolProperties().isLogAbandoned()) {
+ log.warn("Connection has been marked suspect, possibly abandoned " + con + "["+(System.currentTimeMillis()-con.getTimestamp())+" ms.]:" + trace);
+ }
+ if (jmxPool!=null) {
+ jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.SUSPECT_ABANDONED_NOTIFICATION, trace);
+ }
+ con.setSuspect(true);
+ } 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();
+ if (con.release()) {
+ //counter only decremented once
+ size.addAndGet(-1);
+ con.setHandler(null);
+ }
+ } finally {
+ con.unlock();
+ }
+ // we've asynchronously reduced the number of connections
+ // we could have threads stuck in idle.poll(timeout) that will never be
+ // notified
+ if (waitcount.get() > 0) {
+ idle.offer(create(true));
+ }
+ }
+
+ /**
+ * Thread safe way to retrieve a connection from the pool
+ * @param wait - time to wait, overrides the maxWait from the properties,
+ * set to -1 if you wish to use maxWait, 0 if you wish no wait time.
+ * @return PooledConnection
+ * @throws SQLException
+ */
+ private PooledConnection borrowConnection(int wait, String username, String password) 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) {
+ //configure the connection and return it
+ PooledConnection result = borrowConnection(now, con, username, password);
+ //null should never be returned, but was in a previous impl.
+ if (result!=null) return result;
+ }
+
+ //if we get here, see if we need to create one
+ //this is not 100% accurate since it doesn't use a shared
+ //atomic variable - a connection can become idle while we are creating
+ //a new connection
+ if (size.get() < getPoolProperties().getMaxActive()) {
+ //atomic duplicate check
+ if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
+ //if we got here, two threads passed through the first if
+ size.decrementAndGet();
+ } else {
+ //create a connection, we're below the limit
+ return createConnection(now, con, username, password);
+ }
+ } //end if
+
+ //calculate wait time for this iteration
+ long maxWait = wait;
+ //if the passed in wait time is -1, means we should use the pool property value
+ if (wait==-1) {
+ maxWait = (getPoolProperties().getMaxWait()<=0)?Long.MAX_VALUE:getPoolProperties().getMaxWait();
+ }
+
+ long timetowait = Math.max(0, maxWait - (System.currentTimeMillis() - now));
+ waitcount.incrementAndGet();
+ try {
+ //retrieve an existing connection
+ con = idle.poll(timetowait, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ex) {
+ Thread.interrupted();//clear the flag, and bail out
+ SQLException sx = new SQLException("Pool wait interrupted.");
+ sx.initCause(ex);
+ throw sx;
+ } finally {
+ waitcount.decrementAndGet();
+ }
+ if (maxWait==0 && con == null) { //no wait, return one if we have one
+ throw new SQLException("[" + Thread.currentThread().getName()+"] " +
+ "NoWait: Pool empty. Unable to fetch a connection, none available["+busy.size()+" in use].");
+ }
+ //we didn't get a connection, lets see if we timed out
+ if (con == null) {
+ if ((System.currentTimeMillis() - now) >= maxWait) {
+ throw new SQLException("[" + Thread.currentThread().getName()+"] " +
+ "Timeout: 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
+ }
+
+ /**
+ * Creates a JDBC connection and tries to connect to the database.
+ * @param now timestamp of when this was called
+ * @param notUsed Argument not used
+ * @return a PooledConnection that has been connected
+ * @throws SQLException
+ */
+ protected PooledConnection createConnection(long now, PooledConnection notUsed, String username, String password) throws SQLException {
+ //no connections where available we'll create one
+ PooledConnection con = create(false);
+ if (username!=null) con.getAttributes().put(con.PROP_USER, username);
+ if (password!=null) con.getAttributes().put(con.PROP_PASSWORD, password);
+ boolean error = false;
+ try {
+ //connect and validate the connection
+ con.lock();
+ 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());
+ }
+ if (!busy.offer(con)) {
+ log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
+ }
+ return con;
+ } else {
+ //validation failed, make sure we disconnect
+ //and clean up
+ error =true;
+ } //end if
+ } catch (Exception e) {
+ error = true;
+ if (log.isDebugEnabled())
+ log.debug("Unable to create a new JDBC connection.", e);
+ if (e instanceof SQLException) {
+ throw (SQLException)e;
+ } else {
+ SQLException ex = new SQLException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ }
+ } finally {
+ // con can never be null here
+ if (error ) {
+ release(con);
+ }
+ con.unlock();
+ }//catch
+ return null;
+ }
+
+ /**
+ * Validates and configures a previously idle connection
+ * @param now - timestamp
+ * @param con - the connection to validate and configure
+ * @return con
+ * @throws SQLException if a validation error happens
+ */
+ protected PooledConnection borrowConnection(long now, PooledConnection con, String username, String password) throws SQLException {
+ //we have a connection, lets set it up
+
+ //flag to see if we need to nullify
+ boolean setToNull = false;
+ try {
+ con.lock();
+ boolean usercheck = con.checkUser(username, password);
+
+ if (con.isReleased()) {
+ return null;
+ }
+
+ if (!con.isDiscarded() && !con.isInitialized()) {
+ //attempt to connect
+ con.connect();
+ }
+
+ if (usercheck) {
+ if ((!con.isDiscarded()) && 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;
+ }
+ }
+ //if we reached here, that means the connection
+ //is either has another principal, is discarded or validation failed.
+ //we will make one more attempt
+ //in order to guarantee that the thread that just acquired
+ //the connection shouldn't have to poll again.
+ try {
+ con.reconnect();
+ if (con.validate(PooledConnection.VALIDATE_INIT)) {
+ //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 {
+ //validation failed.
+ release(con);
+ setToNull = true;
+ throw new SQLException("Failed to validate a newly established connection.");
+ }
+ } catch (Exception x) {
+ release(con);
+ setToNull = true;
+ if (x instanceof SQLException) {
+ throw (SQLException)x;
+ } else {
+ SQLException ex = new SQLException(x.getMessage());
+ ex.initCause(x);
+ throw ex;
+ }
+ }
+ } finally {
+ con.unlock();
+ if (setToNull) {
+ con = null;
+ }
+ }
+ }
+
+ /**
+ * Determines if a connection should be closed upon return to the pool.
+ * @param con - the connection
+ * @param action - the validation action that should be performed
+ * @return true if the connection should be closed
+ */
+ protected boolean shouldClose(PooledConnection con, int action) {
+ if (con.isDiscarded()) return true;
+ if (isClosed()) return true;
+ if (!con.validate(action)) return true;
+ if (getPoolProperties().getMaxAge()>0 ) {
+ return (System.currentTimeMillis()-con.getLastConnected()) > getPoolProperties().getMaxAge();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns a connection to the pool
+ * If the pool is closed, the connection will be released
+ * If the connection is not part of the busy queue, it will be released.
+ * If {@link PoolProperties#testOnReturn} is set to true it will be validated
+ * @param con PooledConnection to be returned to the pool
+ */
+ 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 (!shouldClose(con,PooledConnection.VALIDATE_RETURN)) {
+ con.setStackTrace(null);
+ con.setTimestamp(System.currentTimeMillis());
+ if (((idle.size()>=poolProperties.getMaxIdle()) && !poolProperties.isPoolSweeperEnabled()) || (!idle.offer(con))) {
+ if (log.isDebugEnabled()) {
+ log.debug("Connection ["+con+"] will be closed and not returned to the pool, idle["+idle.size()+"]>=maxIdle["+poolProperties.getMaxIdle()+"] 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
+
+ /**
+ * Determines if a connection should be abandoned based on
+ * {@link PoolProperties#abandonWhenPercentageFull} setting.
+ * @return true if the connection should be abandoned
+ */
+ protected boolean shouldAbandon() {
+ if (poolProperties.getAbandonWhenPercentageFull()==0) return true;
+ float used = busy.size();
+ float max = poolProperties.getMaxActive();
+ float perc = poolProperties.getAbandonWhenPercentageFull();
+ return (used/max*100f)>=perc;
+ }
+
+ /**
+ * Iterates through all the busy connections and checks for connections that have timed out
+ */
+ public void checkAbandoned() {
+ try {
+ if (busy.size()==0) return;
+ Iterator<PooledConnection> locked = busy.iterator();
+ int sto = getPoolProperties().getSuspectTimeout();
+ 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();
+ long now = System.currentTimeMillis();
+ if (shouldAbandon() && (now - time) > con.getAbandonTimeout()) {
+ busy.remove(con);
+ abandon(con);
+ setToNull = true;
+ } else if (sto > 0 && (now - time) > (sto*1000)) {
+ suspect(con);
+ } 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);
+ }
+ }
+
+ /**
+ * Iterates through the idle connections and resizes the idle pool based on parameters
+ * {@link PoolProperties#maxIdle}, {@link PoolProperties#minIdle}, {@link PoolProperties#minEvictableIdleTimeMillis}
+ */
+ public void checkIdle() {
+ try {
+ if (idle.size()==0) return;
+ 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 ((con.getReleaseTime()>0) && ((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);
+ }
+
+ }
+
+ /**
+ * Forces a validation of all idle connections if {@link PoolProperties#testWhileIdle} is set.
+ */
+ public void testAllIdle() {
+ try {
+ if (idle.size()==0) return;
+ 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);
+ release(con);
+ }
+ } finally {
+ con.unlock();
+ }
+ } //while
+ } catch (ConcurrentModificationException e) {
+ log.debug("testAllIdle failed." ,e);
+ } catch (Exception e) {
+ log.warn("testAllIdle failed, it will be retried.",e);
+ }
+
+ }
+
+ /**
+ * Creates a stack trace representing the existing thread's current state.
+ * @return a string object representing the current state.
+ * TODO investigate if we simply should store {@link java.lang.Thread#getStackTrace()} elements
+ */
+ protected static String getThreadDump() {
+ Exception x = new Exception();
+ x.fillInStackTrace();
+ return getStackTrace(x);
+ }
+
+ /**
+ * Convert an exception into a String
+ * @param x - the throwable
+ * @return a string representing the stack trace
+ */
+ public static String getStackTrace(Throwable 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 (x.getMessage()!=null && x.getMessage().length()>0)? x.getMessage()+";"+result:result;
+ } //end if
+ }
+
+
+ /**
+ * Create a new pooled connection object. Not connected nor validated.
+ * @return a pooled connection object
+ */
+ protected PooledConnection create(boolean incrementCounter) {
+ if (incrementCounter) size.incrementAndGet();
+ PooledConnection con = new PooledConnection(getPoolProperties(), this);
+ return con;
+ }
+
+ /**
+ * Hook to perform final actions on a pooled connection object once it has been disconnected and will be discarded
+ * @param con
+ */
+ protected void finalize(PooledConnection con) {
+ JdbcInterceptor handler = con.getHandler();
+ while (handler!=null) {
+ handler.reset(null, null);
+ handler=handler.getNext();
+ }
+ }
+
+ /**
+ * Hook to perform final actions on a pooled connection object once it has been disconnected and will be discarded
+ * @param con
+ */
+ protected void disconnectEvent(PooledConnection con, boolean finalizing) {
+ JdbcInterceptor handler = con.getHandler();
+ while (handler!=null) {
+ handler.disconnected(this, con, finalizing);
+ handler=handler.getNext();
+ }
+ }
+
+ /**
+ * Return the object that is potentially registered in JMX for notifications
+ * @return the object implementing the {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} interface
+ */
+ public org.apache.tomcat.jdbc.pool.jmx.ConnectionPool getJmxPool() {
+ return jmxPool;
+ }
+
+ /**
+ * Create MBean object that can be registered.
+ */
+ protected void createMBean() {
+ try {
+ jmxPool = new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(this);
+ } catch (Exception x) {
+ log.warn("Unable to start JMX integration for connection pool. Instance["+getName()+"] can't be monitored.",x);
+ }
+ }
+
+ /**
+ * Tread safe wrapper around a future for the regular queue
+ * This one retrieves the pooled connection object
+ * and performs the initialization according to
+ * interceptors and validation rules.
+ * This class is thread safe and is cancellable
+ * @author fhanik
+ *
+ */
+ protected class ConnectionFuture implements Future<Connection>, Runnable {
+ Future<PooledConnection> pcFuture = null;
+ AtomicBoolean configured = new AtomicBoolean(false);
+ CountDownLatch latch = new CountDownLatch(1);
+ Connection result = null;
+ SQLException cause = null;
+ AtomicBoolean cancelled = new AtomicBoolean(false);
+ volatile PooledConnection pc = null;
+ public ConnectionFuture(Future<PooledConnection> pcf) {
+ this.pcFuture = pcf;
+ }
+
+ public ConnectionFuture(PooledConnection pc) throws SQLException {
+ this.pc = pc;
+ result = ConnectionPool.this.setupConnection(pc);
+ configured.set(true);
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ if (pc!=null) {
+ return false;
+ } else if ((!cancelled.get()) && cancelled.compareAndSet(false, true)) {
+ //cancel by retrieving the connection and returning it to the pool
+ ConnectionPool.this.cancellator.execute(this);
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Connection get() throws InterruptedException, ExecutionException {
+ try {
+ return get(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+ }catch (TimeoutException x) {
+ throw new ExecutionException(x);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Connection get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ PooledConnection pc = this.pc!=null?this.pc:pcFuture.get(timeout,unit);
+ if (pc!=null) {
+ if (result!=null) return result;
+ if (configured.compareAndSet(false, true)) {
+ try {
+ pc = borrowConnection(System.currentTimeMillis(),pc, null, null);
+ result = ConnectionPool.this.setupConnection(pc);
+ } catch (SQLException x) {
+ cause = x;
+ } finally {
+ latch.countDown();
+ }
+ } else {
+ //if we reach here, another thread is configuring the actual connection
+ latch.await(timeout,unit); //this shouldn't block for long
+ }
+ if (result==null) throw new ExecutionException(cause);
+ return result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isCancelled() {
+ return pc==null && (pcFuture.isCancelled() || cancelled.get());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isDone() {
+ return pc!=null || pcFuture.isDone();
+ }
+
+ /**
+ * run method to be executed when cancelled by an executor
+ */
+ public void run() {
+ try {
+ Connection con = get(); //complete this future
+ con.close(); //return to the pool
+ }catch (ExecutionException ex) {
+ //we can ignore this
+ }catch (Exception x) {
+ ConnectionPool.log.error("Unable to cancel ConnectionFuture.",x);
+ }
+ }
+
+ }
+
+ protected class PoolCleaner extends Thread {
+ protected ConnectionPool pool;
+ protected long sleepTime;
+ protected volatile boolean run = true;
+ PoolCleaner(String name, ConnectionPool pool, long sleepTime) {
+ super(name);
+ this.setDaemon(true);
+ this.pool = pool;
+ this.sleepTime = sleepTime;
+ if (sleepTime <= 0) {
+ log.warn("Database connection pool evicter thread interval is set to 0, defaulting to 30 seconds");
+ this.sleepTime = 1000 * 30;
+ } else if (sleepTime < 1000) {
+ log.warn("Database connection pool evicter thread interval is set to lower than 1 second.");
+ }
+ }
+
+ @Override
+ public void run() {
+ while (run) {
+ try {
+ sleep(sleepTime);
+ } catch (InterruptedException e) {
+ // ignore it
+ Thread.interrupted();
+ continue;
+ } //catch
+
+ if (pool.isClosed()) {
+ if (pool.getSize() <= 0) {
+ run = false;
+ }
+ } else {
+ try {
+ if (pool.getPoolProperties().isRemoveAbandoned())
+ pool.checkAbandoned();
+ if (pool.getPoolProperties().getMinIdle()<pool.idle.size())
+ pool.checkIdle();
+ if (pool.getPoolProperties().isTestWhileIdle())
+ pool.testAllIdle();
+ } catch (Exception x) {
+ log.error("", x);
+ } //catch
+ } //end if
+ } //while
+ } //run
+
+ public void stopRunning() {
+ run = false;
+ interrupt();
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.util.Hashtable;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+
+/**
+ * A DataSource that can be instantiated through IoC and implements the DataSource interface
+ * since the DataSourceProxy is used as a generic proxy.
+ * The DataSource simply wraps a {@link ConnectionPool} in order to provide a standard interface to the user.
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class DataSource extends DataSourceProxy implements javax.sql.DataSource,MBeanRegistration, org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean {
+ private static final Log log = LogFactory.getLog(DataSource.class);
+
+ /**
+ * Constructor for reflection only. A default set of pool properties will be created.
+ */
+ public DataSource() {
+ super();
+ }
+
+ /**
+ * Constructs a DataSource object wrapping a connection
+ * @param poolProperties
+ */
+ public DataSource(PoolConfiguration poolProperties) {
+ super(poolProperties);
+ }
+
+//===============================================================================
+// JMX Operations - Register the actual pool itself under the tomcat.jdbc domain
+//===============================================================================
+ protected volatile ObjectName oname = null;
+
+ /**
+ * Unregisters the underlying connection pool mbean.<br/>
+ * {@inheritDoc}
+ */
+ public void postDeregister() {
+ if (oname!=null) unregisterJmx();
+ }
+
+ /**
+ * no-op<br/>
+ * {@inheritDoc}
+ */
+ public void postRegister(Boolean registrationDone) {
+ // NOOP
+ }
+
+
+ /**
+ * no-op<br/>
+ * {@inheritDoc}
+ */
+ public void preDeregister() throws Exception {
+ // NOOP
+ }
+
+ /**
+ * If the connection pool MBean exists, it will be registered during this operation.<br/>
+ * {@inheritDoc}
+ */
+ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
+ try {
+ this.oname = createObjectName(name);
+ if (oname!=null) registerJmx();
+ }catch (MalformedObjectNameException x) {
+ log.error("Unable to create object name for JDBC pool.",x);
+ }
+ return name;
+ }
+
+ /**
+ * Creates the ObjectName for the ConnectionPoolMBean object to be registered
+ * @param original the ObjectName for the DataSource
+ * @return the ObjectName for the ConnectionPoolMBean
+ * @throws MalformedObjectNameException
+ */
+ public ObjectName createObjectName(ObjectName original) throws MalformedObjectNameException {
+ String domain = "tomcat.jdbc";
+ Hashtable<String,String> properties = original.getKeyPropertyList();
+ String origDomain = original.getDomain();
+ properties.put("type", "ConnectionPool");
+ properties.put("class", this.getClass().getName());
+ if (original.getKeyProperty("path")!=null) {
+ properties.put("engine", origDomain);
+ }
+ ObjectName name = new ObjectName(domain,properties);
+ return name;
+ }
+
+ /**
+ * Registers the ConnectionPoolMBean under a unique name based on the ObjectName for the DataSource
+ */
+ protected void registerJmx() {
+ try {
+ if (pool.getJmxPool()!=null) {
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ mbs.registerMBean(pool.getJmxPool(), oname);
+ }
+ } catch (Exception e) {
+ log.error("Unable to register JDBC pool with JMX",e);
+ }
+ }
+
+ /**
+ *
+ */
+ protected void unregisterJmx() {
+ try {
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ mbs.unregisterMBean(oname);
+ } catch (InstanceNotFoundException ignore) {
+ // NOOP
+ } catch (Exception e) {
+ log.error("Unable to unregister JDBC pool with JMX",e);
+ }
+ }
+
+
+}
--- /dev/null
+/*
+ * 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.IOException;
+import java.sql.Connection;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.management.ObjectName;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NamingException;
+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>
+ * <li>fairQueue - true of false, whether the pool should sacrifice a little bit of performance for true fairness.</li>
+ *</ol>
+ * @author Craig R. McClanahan
+ * @author Dirk Verbeeck
+ * @author Filip Hanik
+ */
+public class DataSourceFactory implements ObjectFactory {
+ private static final 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_MAXAGE = "maxAge";
+
+ 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_VALIDATOR_CLASS_NAME = "validatorClassName";
+
+ 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_ABANDONWHENPERCENTAGEFULL = "abandonWhenPercentageFull";
+
+ 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";
+ protected final static String PROP_FAIR_QUEUE = "fairQueue";
+
+ protected static final String PROP_USE_EQUALS = "useEquals";
+ protected static final String PROP_USE_CON_LOCK = "useLock";
+
+ protected static final String PROP_DATASOURCE= "dataSource";
+ protected static final String PROP_DATASOURCE_JNDI = "dataSourceJNDI";
+
+ protected static final String PROP_SUSPECT_TIMEOUT = "suspectTimeout";
+
+ protected static final String PROP_ALTERNATE_USERNAME_ALLOWED = "alternateUsernameAllowed";
+
+
+ public static final int UNKNOWN_TRANSACTIONISOLATION = -1;
+
+ public static final String OBJECT_NAME = "object_name";
+
+
+ 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,
+ PROP_FAIR_QUEUE,
+ PROP_USE_EQUALS,
+ OBJECT_NAME,
+ PROP_ABANDONWHENPERCENTAGEFULL,
+ PROP_MAXAGE,
+ PROP_USE_CON_LOCK,
+ PROP_DATASOURCE,
+ PROP_DATASOURCE_JNDI,
+ PROP_ALTERNATE_USERNAME_ALLOWED
+ };
+
+ // -------------------------------------------------- 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;
+ boolean XA = false;
+ boolean ok = false;
+ if ("javax.sql.DataSource".equals(ref.getClassName())) {
+ ok = true;
+ }
+ if ("javax.sql.XADataSource".equals(ref.getClassName())) {
+ ok = true;
+ XA = true;
+ }
+ if (org.apache.tomcat.jdbc.pool.DataSource.class.getName().equals(ref.getClassName())) {
+ ok = true;
+ }
+
+ if (!ok) {
+ log.warn(ref.getClassName()+" is not a valid class name/type for this JNDI factory.");
+ 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,nameCtx,XA);
+ }
+
+ public static PoolConfiguration parsePoolProperties(Properties properties) throws IOException{
+ PoolConfiguration poolProperties = new PoolProperties();
+ String value = null;
+
+ value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT);
+ if (value != null) {
+ poolProperties.setDefaultAutoCommit(Boolean.valueOf(value));
+ }
+
+ value = properties.getProperty(PROP_DEFAULTREADONLY);
+ if (value != null) {
+ poolProperties.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;
+ }
+ }
+ poolProperties.setDefaultTransactionIsolation(level);
+ }
+
+ value = properties.getProperty(PROP_DEFAULTCATALOG);
+ if (value != null) {
+ poolProperties.setDefaultCatalog(value);
+ }
+
+ value = properties.getProperty(PROP_DRIVERCLASSNAME);
+ if (value != null) {
+ poolProperties.setDriverClassName(value);
+ }
+
+ value = properties.getProperty(PROP_MAXACTIVE);
+ if (value != null) {
+ poolProperties.setMaxActive(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_MAXIDLE);
+ if (value != null) {
+ poolProperties.setMaxIdle(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_MINIDLE);
+ if (value != null) {
+ poolProperties.setMinIdle(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_INITIALSIZE);
+ if (value != null) {
+ poolProperties.setInitialSize(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_MAXWAIT);
+ if (value != null) {
+ poolProperties.setMaxWait(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_TESTONBORROW);
+ if (value != null) {
+ poolProperties.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
+ }
+
+ value = properties.getProperty(PROP_TESTONRETURN);
+ if (value != null) {
+ poolProperties.setTestOnReturn(Boolean.valueOf(value).booleanValue());
+ }
+
+ value = properties.getProperty(PROP_TESTONCONNECT);
+ if (value != null) {
+ poolProperties.setTestOnConnect(Boolean.valueOf(value).booleanValue());
+ }
+
+ value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
+ if (value != null) {
+ poolProperties.setTimeBetweenEvictionRunsMillis(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN);
+ if (value != null) {
+ poolProperties.setNumTestsPerEvictionRun(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS);
+ if (value != null) {
+ poolProperties.setMinEvictableIdleTimeMillis(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_TESTWHILEIDLE);
+ if (value != null) {
+ poolProperties.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
+ }
+
+ value = properties.getProperty(PROP_PASSWORD);
+ if (value != null) {
+ poolProperties.setPassword(value);
+ }
+
+ value = properties.getProperty(PROP_URL);
+ if (value != null) {
+ poolProperties.setUrl(value);
+ }
+
+ value = properties.getProperty(PROP_USERNAME);
+ if (value != null) {
+ poolProperties.setUsername(value);
+ }
+
+ value = properties.getProperty(PROP_VALIDATIONQUERY);
+ if (value != null) {
+ poolProperties.setValidationQuery(value);
+ }
+
+ value = properties.getProperty(PROP_VALIDATOR_CLASS_NAME);
+ if (value != null) {
+ poolProperties.setValidatorClassName(value);
+ }
+
+ value = properties.getProperty(PROP_VALIDATIONINTERVAL);
+ if (value != null) {
+ poolProperties.setValidationInterval(Long.parseLong(value));
+ }
+
+ value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
+ if (value != null) {
+ poolProperties.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
+ }
+
+ value = properties.getProperty(PROP_REMOVEABANDONED);
+ if (value != null) {
+ poolProperties.setRemoveAbandoned(Boolean.valueOf(value).booleanValue());
+ }
+
+ value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
+ if (value != null) {
+ poolProperties.setRemoveAbandonedTimeout(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_LOGABANDONED);
+ if (value != null) {
+ poolProperties.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);
+ poolProperties.setDbProperties(p);
+ } else {
+ poolProperties.setDbProperties(new Properties());
+ }
+
+ if (poolProperties.getUsername()!=null) {
+ poolProperties.getDbProperties().setProperty("user",poolProperties.getUsername());
+ }
+ if (poolProperties.getPassword()!=null) {
+ poolProperties.getDbProperties().setProperty("password",poolProperties.getPassword());
+ }
+
+ value = properties.getProperty(PROP_INITSQL);
+ if (value != null) {
+ poolProperties.setInitSQL(value);
+ }
+
+ value = properties.getProperty(PROP_INTERCEPTORS);
+ if (value != null) {
+ poolProperties.setJdbcInterceptors(value);
+ }
+
+ value = properties.getProperty(PROP_JMX_ENABLED);
+ if (value != null) {
+ poolProperties.setJmxEnabled(Boolean.parseBoolean(value));
+ }
+
+ value = properties.getProperty(PROP_FAIR_QUEUE);
+ if (value != null) {
+ poolProperties.setFairQueue(Boolean.parseBoolean(value));
+ }
+
+ value = properties.getProperty(PROP_USE_EQUALS);
+ if (value != null) {
+ poolProperties.setUseEquals(Boolean.parseBoolean(value));
+ }
+
+ value = properties.getProperty(OBJECT_NAME);
+ if (value != null) {
+ poolProperties.setName(ObjectName.quote(value));
+ }
+
+ value = properties.getProperty(PROP_ABANDONWHENPERCENTAGEFULL);
+ if (value != null) {
+ poolProperties.setAbandonWhenPercentageFull(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_MAXAGE);
+ if (value != null) {
+ poolProperties.setMaxAge(Long.parseLong(value));
+ }
+
+ value = properties.getProperty(PROP_USE_CON_LOCK);
+ if (value != null) {
+ poolProperties.setUseLock(Boolean.parseBoolean(value));
+ }
+
+ value = properties.getProperty(PROP_DATASOURCE);
+ if (value != null) {
+ //this should never happen
+ throw new IllegalArgumentException("Can't set dataSource property as a string, this must be a javax.sql.DataSource object.");
+
+ }
+
+ value = properties.getProperty(PROP_DATASOURCE_JNDI);
+ if (value != null) {
+ poolProperties.setDataSourceJNDI(value);
+ }
+
+ value = properties.getProperty(PROP_SUSPECT_TIMEOUT);
+ if (value != null) {
+ poolProperties.setSuspectTimeout(Integer.parseInt(value));
+ }
+
+ value = properties.getProperty(PROP_ALTERNATE_USERNAME_ALLOWED);
+ if (value != null) {
+ poolProperties.setAlternateUsernameAllowed(Boolean.parseBoolean(value));
+ }
+
+ return poolProperties;
+ }
+
+ /**
+ * Creates and configures a {@link DataSource} instance based on the
+ * given properties.
+ *
+ * @param properties the datasource configuration properties
+ * @throws Exception if an error occurs creating the data source
+ */
+ public DataSource createDataSource(Properties properties) throws Exception {
+ return createDataSource(properties,null,false);
+ }
+ public DataSource createDataSource(Properties properties,Context context, boolean XA) throws Exception {
+ PoolConfiguration poolProperties = DataSourceFactory.parsePoolProperties(properties);
+ if (poolProperties.getDataSourceJNDI()!=null && poolProperties.getDataSource()==null) {
+ performJNDILookup(context, poolProperties);
+ }
+ org.apache.tomcat.jdbc.pool.DataSource dataSource = XA?
+ new org.apache.tomcat.jdbc.pool.XADataSource(poolProperties) :
+ new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
+ //initialise the pool itself
+ dataSource.createPool();
+ // Return the configured DataSource instance
+ return dataSource;
+ }
+
+ public void performJNDILookup(Context context, PoolConfiguration poolProperties) {
+ Object jndiDS = null;
+ try {
+ if (context!=null) {
+ jndiDS = context.lookup(poolProperties.getDataSourceJNDI());
+ } else {
+ log.warn("dataSourceJNDI property is configued, but local JNDI context is null.");
+ }
+ } catch (NamingException e) {
+ log.debug("The name \""+poolProperties.getDataSourceJNDI()+"\" can not be found in the local context.");
+ }
+ if (jndiDS==null) {
+ try {
+ context = (Context) (new InitialContext());
+ jndiDS = context.lookup(poolProperties.getDataSourceJNDI());
+ } catch (NamingException e) {
+ log.warn("The name \""+poolProperties.getDataSourceJNDI()+"\" can not be found in the InitialContext.");
+ }
+ }
+ if (jndiDS!=null) {
+ poolProperties.setDataSource(jndiDS);
+ }
+ }
+
+ /**
+ * <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 IOException {
+ return PoolProperties.getProperties(propText,null);
+ }
+
+}
--- /dev/null
+/*
+ * 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 java.util.Properties;
+import java.util.concurrent.Future;
+
+import javax.sql.XAConnection;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
+
+/**
+ *
+ * The DataSource proxy lets us implements methods that don't exist in the current
+ * compiler JDK but might be methods that are part of a future JDK DataSource interface.
+ * <br/>
+ * It's a trick to work around compiler issues when implementing interfaces. For example,
+ * I could put in Java 6 methods of javax.sql.DataSource here, and compile it with JDK 1.5
+ * and still be able to run under Java 6 without getting NoSuchMethodException.
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public class DataSourceProxy implements PoolConfiguration {
+ private static final Log log = LogFactory.getLog(DataSourceProxy.class);
+
+ protected volatile ConnectionPool pool = null;
+
+ protected PoolConfiguration poolProperties = null;
+
+ public DataSourceProxy() {
+ this(new PoolProperties());
+ }
+
+ public DataSourceProxy(PoolConfiguration poolProperties) {
+ if (poolProperties == null) throw new NullPointerException("PoolConfiguration can not be null.");
+ this.poolProperties = poolProperties;
+ }
+
+
+ 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;
+ }
+
+ /**
+ * {@link javax.sql.DataSource#getConnection()}
+ */
+ public Connection getConnection(String username, String password) throws SQLException {
+ if (this.getPoolProperties().isAlternateUsernameAllowed()) {
+ if (pool == null)
+ return createPool().getConnection(username,password);
+ return pool.getConnection(username,password);
+ } else {
+ return getConnection();
+ }
+ }
+
+ public PoolConfiguration getPoolProperties() {
+ return poolProperties;
+ }
+
+ /**
+ * Sets up the connection pool, by creating a pooling driver.
+ * @return Driver
+ * @throws SQLException
+ */
+ public synchronized ConnectionPool createPool() throws SQLException {
+ if (pool != null) {
+ return pool;
+ } else {
+ pool = new ConnectionPool(poolProperties);
+ return pool;
+ }
+ }
+
+ /**
+ * {@link javax.sql.DataSource#getConnection()}
+ */
+
+ public Connection getConnection() throws SQLException {
+ if (pool == null)
+ return createPool().getConnection();
+ return pool.getConnection();
+ }
+
+ /**
+ * Invokes an sync operation to retrieve the connection.
+ * @return a Future containing a reference to the connection when it becomes available
+ * @throws SQLException
+ */
+ public Future<Connection> getConnectionAsync() throws SQLException {
+ if (pool == null)
+ return createPool().getConnectionAsync();
+ return pool.getConnectionAsync();
+ }
+
+ /**
+ * {@link javax.sql.XADataSource#getXAConnection()}
+ */
+ public XAConnection getXAConnection() throws SQLException {
+ Connection con = getConnection();
+ if (con instanceof XAConnection) {
+ return (XAConnection)con;
+ } else {
+ try {con.close();} catch (Exception ignore){}
+ throw new SQLException("Connection from pool does not implement javax.sql.XAConnection");
+ }
+ }
+
+ /**
+ * {@link javax.sql.XADataSource#getXAConnection(String, String)}
+ */
+ public XAConnection getXAConnection(String username, String password) throws SQLException {
+ Connection con = getConnection(username, password);
+ if (con instanceof XAConnection) {
+ return (XAConnection)con;
+ } else {
+ try {con.close();} catch (Exception ignore){}
+ throw new SQLException("Connection from pool does not implement javax.sql.XAConnection");
+ }
+ }
+
+
+ /**
+ * {@link javax.sql.DataSource#getConnection()}
+ */
+ public PooledConnection getPooledConnection() throws SQLException {
+ return (PooledConnection) getConnection();
+ }
+
+ /**
+ * {@link javax.sql.DataSource#getConnection()}
+ */
+ public PooledConnection getPooledConnection(String username,
+ String password) throws SQLException {
+ return (PooledConnection) getConnection();
+ }
+
+ public ConnectionPool getPool() {
+ return pool;
+ }
+
+
+ public void close() {
+ close(false);
+ }
+ public void close(boolean all) {
+ try {
+ if (pool != null) {
+ final ConnectionPool p = pool;
+ pool = null;
+ if (p!=null) {
+ p.close(all);
+ }
+ }
+ }catch (Exception x) {
+ log.warn("Error duing connection pool closure.", x);
+ }
+ }
+
+ public int getPoolSize() throws SQLException{
+ final ConnectionPool p = pool;
+ if (p == null) return 0;
+ else return p.getSize();
+ }
+
+
+ public String toString() {
+ return super.toString()+"{"+getPoolProperties()+"}";
+ }
+
+
+/*-----------------------------------------------------------------------*/
+// PROPERTIES WHEN NOT USED WITH FACTORY
+/*------------------------------------------------------------------------*/
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getPoolName() {
+ return pool.getName();
+ }
+
+
+ public void setPoolProperties(PoolConfiguration poolProperties) {
+ this.poolProperties = poolProperties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDriverClassName(String driverClassName) {
+ this.poolProperties.setDriverClassName(driverClassName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setInitialSize(int initialSize) {
+ this.poolProperties.setInitialSize(initialSize);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setInitSQL(String initSQL) {
+ this.poolProperties.setInitSQL(initSQL);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setLogAbandoned(boolean logAbandoned) {
+ this.poolProperties.setLogAbandoned(logAbandoned);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMaxActive(int maxActive) {
+ this.poolProperties.setMaxActive(maxActive);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMaxIdle(int maxIdle) {
+ this.poolProperties.setMaxIdle(maxIdle);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMaxWait(int maxWait) {
+ this.poolProperties.setMaxWait(maxWait);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
+ this.poolProperties.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMinIdle(int minIdle) {
+ this.poolProperties.setMinIdle(minIdle);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+ this.poolProperties.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setPassword(String password) {
+ this.poolProperties.setPassword(password);
+ this.poolProperties.getDbProperties().setProperty("password",this.poolProperties.getPassword());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setRemoveAbandoned(boolean removeAbandoned) {
+ this.poolProperties.setRemoveAbandoned(removeAbandoned);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
+ this.poolProperties.setRemoveAbandonedTimeout(removeAbandonedTimeout);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTestOnBorrow(boolean testOnBorrow) {
+ this.poolProperties.setTestOnBorrow(testOnBorrow);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTestOnConnect(boolean testOnConnect) {
+ this.poolProperties.setTestOnConnect(testOnConnect);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTestOnReturn(boolean testOnReturn) {
+ this.poolProperties.setTestOnReturn(testOnReturn);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTestWhileIdle(boolean testWhileIdle) {
+ this.poolProperties.setTestWhileIdle(testWhileIdle);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
+ this.poolProperties.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setUrl(String url) {
+ this.poolProperties.setUrl(url);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setUsername(String username) {
+ this.poolProperties.setUsername(username);
+ this.poolProperties.getDbProperties().setProperty("user",getPoolProperties().getUsername());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setValidationInterval(long validationInterval) {
+ this.poolProperties.setValidationInterval(validationInterval);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setValidationQuery(String validationQuery) {
+ this.poolProperties.setValidationQuery(validationQuery);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setValidatorClassName(String className) {
+ this.poolProperties.setValidatorClassName(className);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setJdbcInterceptors(String interceptors) {
+ this.getPoolProperties().setJdbcInterceptors(interceptors);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setJmxEnabled(boolean enabled) {
+ this.getPoolProperties().setJmxEnabled(enabled);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setFairQueue(boolean fairQueue) {
+ this.getPoolProperties().setFairQueue(fairQueue);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setUseLock(boolean useLock) {
+ this.getPoolProperties().setUseLock(useLock);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDefaultCatalog(String catalog) {
+ this.getPoolProperties().setDefaultCatalog(catalog);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDefaultAutoCommit(Boolean autocommit) {
+ this.getPoolProperties().setDefaultAutoCommit(autocommit);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
+ this.getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ 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);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setUseEquals(boolean useEquals) {
+ this.getPoolProperties().setUseEquals(useEquals);
+ }
+
+ /**
+ * no-op
+ * {@link javax.sql.DataSource#getLogWriter}
+ */
+ public PrintWriter getLogWriter() throws SQLException {
+ return null;
+ }
+
+
+ /**
+ * no-op
+ * {@link javax.sql.DataSource#setLogWriter(PrintWriter)}
+ */
+ public void setLogWriter(PrintWriter out) throws SQLException {
+ // NOOP
+ }
+
+ /**
+ * no-op
+ * {@link javax.sql.DataSource#getLoginTimeout}
+ */
+ public int getLoginTimeout() {
+ if (poolProperties == null) {
+ return 0;
+ } else {
+ return poolProperties.getMaxWait() / 1000;
+ }
+ }
+
+ /**
+ * {@link javax.sql.DataSource#setLoginTimeout(int)}
+ */
+ public void setLoginTimeout(int i) {
+ if (poolProperties == null) {
+ return;
+ } else {
+ poolProperties.setMaxWait(1000 * i);
+ }
+
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getSuspectTimeout() {
+ return getPoolProperties().getSuspectTimeout();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setSuspectTimeout(int seconds) {
+ getPoolProperties().setSuspectTimeout(seconds);
+ }
+
+ //===============================================================================
+// Expose JMX attributes through Tomcat's dynamic reflection
+//===============================================================================
+ /**
+ * If the pool has not been created, it will be created during this call.
+ * @return the number of established but idle connections
+ */
+ public int getIdle() {
+ try {
+ return createPool().getIdle();
+ }catch (SQLException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * {@link #getIdle()}
+ */
+ public int getNumIdle() {
+ return getIdle();
+ }
+
+ /**
+ * Forces an abandon check on the connection pool.
+ * If connections that have been abandoned exists, they will be closed during this run
+ */
+ public void checkAbandoned() {
+ try {
+ createPool().checkAbandoned();
+ }catch (SQLException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * Forces a check for resizing of the idle connections
+ */
+ public void checkIdle() {
+ try {
+ createPool().checkIdle();
+ }catch (SQLException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * @return number of connections in use by the application
+ */
+ public int getActive() {
+ try {
+ return createPool().getActive();
+ }catch (SQLException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * @return number of connections in use by the application
+ * {@link DataSource#getActive()}
+ */
+ public int getNumActive() {
+ return getActive();
+ }
+
+ /**
+ * @return number of threads waiting for a connection
+ */
+ public int getWaitCount() {
+ try {
+ return createPool().getWaitCount();
+ }catch (SQLException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * @return the current size of the pool
+ */
+ public int getSize() {
+ try {
+ return createPool().getSize();
+ }catch (SQLException x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * Performs a validation on idle connections
+ */
+ public void testIdle() {
+ try {
+ createPool().testAllIdle();
+ }catch (SQLException x) {
+ throw new RuntimeException(x);
+ }
+ }
+ //=========================================================
+ // PROPERTIES / CONFIGURATION
+ //=========================================================
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getConnectionProperties() {
+ return getPoolProperties().getConnectionProperties();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Properties getDbProperties() {
+ return getPoolProperties().getDbProperties();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getDefaultCatalog() {
+ return getPoolProperties().getDefaultCatalog();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getDefaultTransactionIsolation() {
+ return getPoolProperties().getDefaultTransactionIsolation();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getDriverClassName() {
+ return getPoolProperties().getDriverClassName();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getInitialSize() {
+ return getPoolProperties().getInitialSize();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getInitSQL() {
+ return getPoolProperties().getInitSQL();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getJdbcInterceptors() {
+ return getPoolProperties().getJdbcInterceptors();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMaxActive() {
+ return getPoolProperties().getMaxActive();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMaxIdle() {
+ return getPoolProperties().getMaxIdle();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMaxWait() {
+ return getPoolProperties().getMaxWait();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMinEvictableIdleTimeMillis() {
+ return getPoolProperties().getMinEvictableIdleTimeMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMinIdle() {
+ return getPoolProperties().getMinIdle();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public long getMaxAge() {
+ return getPoolProperties().getMaxAge();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getName() {
+ return getPoolProperties().getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getNumTestsPerEvictionRun() {
+ return getPoolProperties().getNumTestsPerEvictionRun();
+ }
+
+ /**
+ * @return DOES NOT RETURN THE PASSWORD, IT WOULD SHOW UP IN JMX
+ */
+ public String getPassword() {
+ return "Password not available as DataSource/JMX operation.";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getRemoveAbandonedTimeout() {
+ return getPoolProperties().getRemoveAbandonedTimeout();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getTimeBetweenEvictionRunsMillis() {
+ return getPoolProperties().getTimeBetweenEvictionRunsMillis();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getUrl() {
+ return getPoolProperties().getUrl();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getUsername() {
+ return getPoolProperties().getUsername();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public long getValidationInterval() {
+ return getPoolProperties().getValidationInterval();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getValidationQuery() {
+ return getPoolProperties().getValidationQuery();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getValidatorClassName() {
+ return getPoolProperties().getValidatorClassName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Validator getValidator() {
+ return getPoolProperties().getValidator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isAccessToUnderlyingConnectionAllowed() {
+ return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Boolean isDefaultAutoCommit() {
+ return getPoolProperties().isDefaultAutoCommit();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Boolean isDefaultReadOnly() {
+ return getPoolProperties().isDefaultReadOnly();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isLogAbandoned() {
+ return getPoolProperties().isLogAbandoned();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isPoolSweeperEnabled() {
+ return getPoolProperties().isPoolSweeperEnabled();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isRemoveAbandoned() {
+ return getPoolProperties().isRemoveAbandoned();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getAbandonWhenPercentageFull() {
+ return getPoolProperties().getAbandonWhenPercentageFull();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isTestOnBorrow() {
+ return getPoolProperties().isTestOnBorrow();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isTestOnConnect() {
+ return getPoolProperties().isTestOnConnect();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isTestOnReturn() {
+ return getPoolProperties().isTestOnReturn();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isTestWhileIdle() {
+ return getPoolProperties().isTestWhileIdle();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Boolean getDefaultAutoCommit() {
+ return getPoolProperties().getDefaultAutoCommit();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Boolean getDefaultReadOnly() {
+ return getPoolProperties().getDefaultReadOnly();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
+ return getPoolProperties().getJdbcInterceptorsAsArray();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean getUseLock() {
+ return getPoolProperties().getUseLock();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isFairQueue() {
+ return getPoolProperties().isFairQueue();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isJmxEnabled() {
+ return getPoolProperties().isJmxEnabled();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isUseEquals() {
+ return getPoolProperties().isUseEquals();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setAbandonWhenPercentageFull(int percentage) {
+ getPoolProperties().setAbandonWhenPercentageFull(percentage);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
+ getPoolProperties().setAccessToUnderlyingConnectionAllowed(accessToUnderlyingConnectionAllowed);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDbProperties(Properties dbProperties) {
+ getPoolProperties().setDbProperties(dbProperties);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDefaultReadOnly(Boolean defaultReadOnly) {
+ getPoolProperties().setDefaultReadOnly(defaultReadOnly);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMaxAge(long maxAge) {
+ getPoolProperties().setMaxAge(maxAge);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setName(String name) {
+ getPoolProperties().setName(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDataSource(Object ds) {
+ getPoolProperties().setDataSource(ds);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getDataSource() {
+ return getPoolProperties().getDataSource();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDataSourceJNDI(String jndiDS) {
+ getPoolProperties().setDataSourceJNDI(jndiDS);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getDataSourceJNDI() {
+ return getPoolProperties().getDataSourceJNDI();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isAlternateUsernameAllowed() {
+ return getPoolProperties().isAlternateUsernameAllowed();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
+ getPoolProperties().setAlternateUsernameAllowed(alternateUsernameAllowed);
+ }
+
+}
--- /dev/null
+/*
+ * 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.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ *
+ * A simple implementation of a blocking queue with fairness waiting.
+ * invocations to method poll(...) will get handed out in the order they were received.
+ * Locking is fine grained, a shared lock is only used during the first level of contention, waiting is done in a
+ * lock per thread basis so that order is guaranteed once the thread goes into a suspended monitor state.
+ * <br/>
+ * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented.
+ * @author Filip Hanik
+ *
+ */
+
+public class FairBlockingQueue<E> implements BlockingQueue<E> {
+
+ /**
+ * This little sucker is used to reorder the way to do
+ * {@link java.util.concurrent.locks.Lock#lock()},
+ * {@link java.util.concurrent.locks.Lock#unlock()}
+ * and
+ * {@link java.util.concurrent.CountDownLatch#countDown()}
+ * during the {@link #poll(long, TimeUnit)} operation.
+ * On Linux, it performs much better if we count down while we hold the global
+ * lock, on Solaris its the other way around.
+ * Until we have tested other platforms we only check for Linux.
+ */
+ final static boolean isLinux = "Linux".equals(System.getProperty("os.name")) &&
+ (!Boolean.getBoolean(FairBlockingQueue.class.getName()+".ignoreOS"));
+
+ /**
+ * Phase one entry lock in order to give out
+ * per-thread-locks for the waiting phase we have
+ * a phase one lock during the contention period.
+ */
+ final ReentrantLock lock = new ReentrantLock(false);
+
+ /**
+ * All the objects in the pool are stored in a simple linked list
+ */
+ final LinkedList<E> items;
+
+ /**
+ * All threads waiting for an object are stored in a linked list
+ */
+ final LinkedList<ExchangeCountDownLatch<E>> waiters;
+
+ /**
+ * Creates a new fair blocking queue.
+ */
+ public FairBlockingQueue() {
+ items = new LinkedList<E>();
+ waiters = new LinkedList<ExchangeCountDownLatch<E>>();
+ }
+
+ //------------------------------------------------------------------
+ // USED BY CONPOOL IMPLEMENTATION
+ //------------------------------------------------------------------
+ /**
+ * Will always return true, queue is unbounded.
+ * {@inheritDoc}
+ */
+ public boolean offer(E e) {
+ //during the offer, we will grab the main lock
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ ExchangeCountDownLatch<E> c = null;
+ try {
+ //check to see if threads are waiting for an object
+ if (waiters.size() > 0) {
+ //if threads are waiting grab the latch for that thread
+ c = waiters.poll();
+ //give the object to the thread instead of adding it to the pool
+ c.setItem(e);
+ if (isLinux) c.countDown();
+ } else {
+ //we always add first, so that the most recently used object will be given out
+ items.addFirst(e);
+ }
+ } finally {
+ lock.unlock();
+ }
+ //if we exchanged an object with another thread, wake it up.
+ if (!isLinux && c!=null) c.countDown();
+ //we have an unbounded queue, so always return true
+ return true;
+ }
+
+ /**
+ * Will never timeout, as it invokes the {@link #offer(Object)} method.
+ * Once a lock has been acquired, the
+ * {@inheritDoc}
+ */
+ public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
+ return offer(e);
+ }
+
+ /**
+ * Fair retrieval of an object in the queue.
+ * Objects are returned in the order the threads requested them.
+ * {@inheritDoc}
+ */
+ public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+ E result = null;
+ final ReentrantLock lock = this.lock;
+ boolean error = true;
+ //acquire the global lock until we know what to do
+ lock.lock();
+ try {
+ //check to see if we have objects
+ result = items.poll();
+ if (result==null && timeout>0) {
+ //the queue is empty we will wait for an object
+ ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<E>(1);
+ //add to the bottom of the wait list
+ waiters.addLast(c);
+ //unlock the global lock
+ lock.unlock();
+ //wait for the specified timeout
+ if (!c.await(timeout, unit)) {
+ //if we timed out, remove ourselves from the waitlist
+ lock.lock();
+ waiters.remove(c);
+ lock.unlock();
+ }
+ //return the item we received, can be null if we timed out
+ result = c.getItem();
+ } else {
+ //we have an object, release
+ lock.unlock();
+ }
+ error = false;
+ } finally {
+ if (error && lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Request an item from the queue asynchronously
+ * @return - a future pending the result from the queue poll request
+ */
+ public Future<E> pollAsync() {
+ Future<E> result = null;
+ final ReentrantLock lock = this.lock;
+ boolean error = true;
+ //grab the global lock
+ lock.lock();
+ try {
+ //check to see if we have objects in the queue
+ E item = items.poll();
+ if (item==null) {
+ //queue is empty, add ourselves as waiters
+ ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<E>(1);
+ waiters.addLast(c);
+ lock.unlock();
+ //return a future that will wait for the object
+ result = new ItemFuture<E>(c);
+ } else {
+ lock.unlock();
+ //return a future with the item
+ result = new ItemFuture<E>(item);
+ }
+ error = false;
+ } finally {
+ if (error && lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean remove(Object e) {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return items.remove(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size() {
+ return items.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<E> iterator() {
+ return new FairIterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public E poll() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return items.poll();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean contains(Object e) {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ return items.contains(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+
+ //------------------------------------------------------------------
+ // NOT USED BY CONPOOL IMPLEMENTATION
+ //------------------------------------------------------------------
+ /**
+ * {@inheritDoc}
+ */
+ public boolean add(E e) {
+ return offer(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public int drainTo(Collection<? super E> c, int maxElements) {
+ throw new UnsupportedOperationException("int drainTo(Collection<? super E> c, int maxElements)");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+
+ public int drainTo(Collection<? super E> c) {
+ return drainTo(c,Integer.MAX_VALUE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void put(E e) throws InterruptedException {
+ offer(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int remainingCapacity() {
+ return Integer.MAX_VALUE - size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public E take() throws InterruptedException {
+ return this.poll(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addAll(Collection<? extends E> c) {
+ Iterator<? extends E> i = c.iterator();
+ while (i.hasNext()) {
+ E e = i.next();
+ offer(e);
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public void clear() {
+ throw new UnsupportedOperationException("void clear()");
+
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public boolean containsAll(Collection<?> c) {
+ throw new UnsupportedOperationException("boolean containsAll(Collection<?> c)");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException("boolean removeAll(Collection<?> c)");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException("boolean retainAll(Collection<?> c)");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public Object[] toArray() {
+ throw new UnsupportedOperationException("Object[] toArray()");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public <T> T[] toArray(T[] a) {
+ throw new UnsupportedOperationException("<T> T[] toArray(T[] a)");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public E element() {
+ throw new UnsupportedOperationException("E element()");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public E peek() {
+ throw new UnsupportedOperationException("E peek()");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public E remove() {
+ throw new UnsupportedOperationException("E remove()");
+ }
+
+
+
+ //------------------------------------------------------------------
+ // Non cancellable Future used to check and see if a connection has been made available
+ //------------------------------------------------------------------
+ protected class ItemFuture<T> implements Future<T> {
+ protected volatile T item = null;
+ protected volatile ExchangeCountDownLatch<T> latch = null;
+ protected volatile boolean canceled = false;
+
+ public ItemFuture(T item) {
+ this.item = item;
+ }
+
+ public ItemFuture(ExchangeCountDownLatch<T> latch) {
+ this.latch = latch;
+ }
+
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false; //don't allow cancel for now
+ }
+
+ public T get() throws InterruptedException, ExecutionException {
+ if (item!=null) {
+ return item;
+ } else if (latch!=null) {
+ latch.await();
+ return latch.getItem();
+ } else {
+ throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
+ }
+ }
+
+ public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ if (item!=null) {
+ return item;
+ } else if (latch!=null) {
+ boolean timedout = !latch.await(timeout, unit);
+ if (timedout) throw new TimeoutException();
+ else return latch.getItem();
+ } else {
+ throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
+ }
+ }
+
+ public boolean isCancelled() {
+ return false;
+ }
+
+ public boolean isDone() {
+ return (item!=null || latch.getItem()!=null);
+ }
+
+ }
+
+ //------------------------------------------------------------------
+ // Count down latch that can be used to exchange information
+ //------------------------------------------------------------------
+ protected class ExchangeCountDownLatch<T> extends CountDownLatch {
+ protected volatile T item;
+ public ExchangeCountDownLatch(int i) {
+ super(i);
+ }
+ public T getItem() {
+ return item;
+ }
+ public void setItem(T item) {
+ this.item = item;
+ }
+ }
+
+ //------------------------------------------------------------------
+ // Iterator safe from concurrent modification exceptions
+ //------------------------------------------------------------------
+ protected class FairIterator implements Iterator<E> {
+ E[] elements = null;
+ int index;
+ E element = null;
+
+ public FairIterator() {
+ final ReentrantLock lock = FairBlockingQueue.this.lock;
+ lock.lock();
+ try {
+ elements = (E[]) new Object[FairBlockingQueue.this.items.size()];
+ FairBlockingQueue.this.items.toArray(elements);
+ index = 0;
+ } finally {
+ lock.unlock();
+ }
+ }
+ public boolean hasNext() {
+ return index<elements.length;
+ }
+
+ public E next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ element = elements[index++];
+ return element;
+ }
+
+ public void remove() {
+ final ReentrantLock lock = FairBlockingQueue.this.lock;
+ lock.lock();
+ try {
+ if (element!=null) {
+ FairBlockingQueue.this.items.remove(element);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ }
+}
--- /dev/null
+/*
+ * 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;
+import java.util.Map;
+
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+
+/**
+ * Abstract class that is to be extended for implementations of interceptors.
+ * Everytime an operation is called on the {@link java.sql.Connection} object the
+ * {@link #invoke(Object, Method, Object[])} method on the interceptor will be called.
+ * Interceptors are useful to change or improve behavior of the connection pool.<br/>
+ * Interceptors can receive a set of properties. Each sub class is responsible for parsing the properties during runtime when they
+ * are needed or simply override the {@link #setProperties(Map)} method.
+ * Properties arrive in a key-value pair of Strings as they were received through the configuration.
+ * This method is called once per cached connection object when the object is first configured.
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public abstract class JdbcInterceptor implements InvocationHandler {
+ /**
+ * {@link java.sql.Connection#close()} method name
+ */
+ public static final String CLOSE_VAL = "close";
+ /**
+ * {@link Object#toString()} method name
+ */
+ public static final String TOSTRING_VAL = "toString";
+ /**
+ * {@link java.sql.Connection#isClosed()} method name
+ */
+ public static final String ISCLOSED_VAL = "isClosed";
+ /**
+ * {@link javax.sql.PooledConnection#getConnection()} method name
+ */
+ public static final String GETCONNECTION_VAL = "getConnection";
+ /**
+ * {@link java.sql.Wrapper#unwrap(Class)} method name
+ */
+ public static final String UNWRAP_VAL = "unwrap";
+ /**
+ * {@link java.sql.Wrapper#isWrapperFor(Class)} method name
+ */
+ public static final String ISWRAPPERFOR_VAL = "isWrapperFor";
+
+
+ /**
+ * Properties for this interceptor.
+ */
+ protected Map<String,InterceptorProperty> properties = null;
+
+ /**
+ * The next interceptor in the chain
+ */
+ private JdbcInterceptor next = null;
+ /**
+ * Property that decides how we do string comparison, default is to use
+ * {@link String#equals(Object)}. If set to <code>false</code> then the
+ * equality operator (==) is used.
+ */
+ private boolean useEquals = true;
+
+ /**
+ * Public constructor for instantation through reflection
+ */
+ public JdbcInterceptor() {
+ // NOOP
+ }
+
+ /**
+ * Gets invoked each time an operation on {@link java.sql.Connection} is invoked.
+ * {@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();
+ }
+
+ /**
+ * Returns the next interceptor in the chain
+ * @return the next interceptor in the chain
+ */
+ public JdbcInterceptor getNext() {
+ return next;
+ }
+
+ /**
+ * configures the next interceptor in the chain
+ * @param next
+ */
+ public void setNext(JdbcInterceptor next) {
+ this.next = next;
+ }
+
+ /**
+ * Performs a string comparison, using references unless the useEquals property is set to true.
+ * @param name1
+ * @param name2
+ * @return true if name1 is equal to name2 based on {@link #useEquals}
+ */
+ public boolean compare(String name1, String name2) {
+ if (isUseEquals()) {
+ return name1.equals(name2);
+ } else {
+ return name1==name2;
+ }
+ }
+
+ /**
+ * Compares a method name (String) to a method (Method)
+ * {@link #compare(String,String)}
+ * Uses reference comparison unless the useEquals property is set to true
+ * @param methodName
+ * @param method
+ * @return true if the name matches
+ */
+ public boolean compare(String methodName, Method method) {
+ return compare(methodName, method.getName());
+ }
+
+ /**
+ * Gets called each time the connection is borrowed from the pool
+ * This means that if an interceptor holds a reference to the connection
+ * the interceptor can be reused for another connection.
+ * <br/>
+ * This method may be called with null as both arguments when we are closing down the connection.
+ * @param parent - the connection pool owning the connection
+ * @param con - the pooled connection
+ */
+ public abstract void reset(ConnectionPool parent, PooledConnection con);
+
+ /**
+ * Called when {@link java.sql.Connection#close()} is called on the underlying connection.
+ * This is to notify the interceptors, that the physical connection has been released.
+ * Implementation of this method should be thought through with care, as no actions should trigger an exception.
+ * @param parent - the connection pool that this connection belongs to
+ * @param con - the pooled connection that holds this connection
+ * @param finalizing - if this connection is finalizing. True means that the pooled connection will not reconnect the underlying connection
+ */
+ public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {
+ }
+
+
+ /**
+ * Returns the properties configured for this interceptor
+ * @return the configured properties for this interceptor
+ */
+ public Map<String,InterceptorProperty> getProperties() {
+ return properties;
+ }
+
+ /**
+ * Called during the creation of an interceptor
+ * The properties can be set during the configuration of an interceptor
+ * Override this method to perform type casts between string values and object properties
+ * @param properties
+ */
+ public void setProperties(Map<String,InterceptorProperty> properties) {
+ this.properties = properties;
+ final String useEquals = "useEquals";
+ InterceptorProperty p = properties.get(useEquals);
+ if (p!=null) {
+ setUseEquals(Boolean.parseBoolean(p.getValue()));
+ }
+ }
+
+ /**
+ * @return true if the compare method uses the Object.equals(Object) method
+ * false if comparison is done on a reference level
+ */
+ public boolean isUseEquals() {
+ return useEquals;
+ }
+
+ /**
+ * Set to true if string comparisons (for the {@link #compare(String, Method)} and {@link #compare(String, String)} methods) should use the Object.equals(Object) method
+ * The default is false
+ * @param useEquals
+ */
+ public void setUseEquals(boolean useEquals) {
+ this.useEquals = useEquals;
+ }
+
+ /**
+ * This method is invoked by a connection pool when the pool is closed.
+ * Interceptor classes can override this method if they keep static
+ * variables or other tracking means around.
+ * <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>
+ * @param pool - the pool that is being closed.
+ */
+ public void poolClosed(ConnectionPool pool) {
+ // NOOP
+ }
+
+ /**
+ * This method is invoked by a connection pool when the pool is first started up, usually when the first connection is requested.
+ * Interceptor classes can override this method if they keep static
+ * variables or other tracking means around.
+ * <b>This method is only invoked on a single instance of the interceptor, and not on every instance created.</b>
+ * @param pool - the pool that is being closed.
+ */
+ public void poolStarted(ConnectionPool pool) {
+ // NOOP
+ }
+
+}
--- /dev/null
+/*
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * <b>EXPERIMENTAL AND NOT YET COMPLETE!</b>
+ *
+ *
+ * An implementation of a blocking queue with fairness waiting and lock dispersal to avoid contention.
+ * invocations to method poll(...) will get handed out in the order they were received.
+ * Locking is fine grained, a shared lock is only used during the first level of contention, waiting is done in a
+ * lock per thread basis so that order is guaranteed once the thread goes into a suspended monitor state.
+ * <br/>
+ * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented.
+ * @author Filip Hanik
+ *
+ */
+
+public class MultiLockFairBlockingQueue<E> implements BlockingQueue<E> {
+
+ final int LOCK_COUNT = Runtime.getRuntime().availableProcessors();
+
+ final AtomicInteger putQueue = new AtomicInteger(0);
+ final AtomicInteger pollQueue = new AtomicInteger(0);
+
+ public int getNextPut() {
+ int idx = Math.abs(putQueue.incrementAndGet()) % LOCK_COUNT;
+ return idx;
+ }
+
+ public int getNextPoll() {
+ int idx = Math.abs(pollQueue.incrementAndGet()) % LOCK_COUNT;
+ return idx;
+ }
+ /**
+ * Phase one entry lock in order to give out
+ * per-thread-locks for the waiting phase we have
+ * a phase one lock during the contention period.
+ */
+ private final ReentrantLock[] locks = new ReentrantLock[LOCK_COUNT];
+
+ /**
+ * All the objects in the pool are stored in a simple linked list
+ */
+ final LinkedList<E>[] items;
+
+ /**
+ * All threads waiting for an object are stored in a linked list
+ */
+ final LinkedList<ExchangeCountDownLatch<E>>[] waiters;
+
+ /**
+ * Creates a new fair blocking queue.
+ */
+ public MultiLockFairBlockingQueue() {
+ items = new LinkedList[LOCK_COUNT];
+ waiters = new LinkedList[LOCK_COUNT];
+ for (int i=0; i<LOCK_COUNT; i++) {
+ items[i] = new LinkedList<E>();
+ waiters[i] = new LinkedList<ExchangeCountDownLatch<E>>();
+ locks[i] = new ReentrantLock(false);
+ }
+ }
+
+ //------------------------------------------------------------------
+ // USED BY CONPOOL IMPLEMENTATION
+ //------------------------------------------------------------------
+ /**
+ * Will always return true, queue is unbounded.
+ * {@inheritDoc}
+ */
+ public boolean offer(E e) {
+ int idx = getNextPut();
+ //during the offer, we will grab the main lock
+ final ReentrantLock lock = this.locks[idx];
+ lock.lock();
+ ExchangeCountDownLatch<E> c = null;
+ try {
+ //check to see if threads are waiting for an object
+ if (waiters[idx].size() > 0) {
+ //if threads are waiting grab the latch for that thread
+ c = waiters[idx].poll();
+ //give the object to the thread instead of adding it to the pool
+ c.setItem(e);
+ } else {
+ //we always add first, so that the most recently used object will be given out
+ items[idx].addFirst(e);
+ }
+ } finally {
+ lock.unlock();
+ }
+ //if we exchanged an object with another thread, wake it up.
+ if (c!=null) c.countDown();
+ //we have an unbounded queue, so always return true
+ return true;
+ }
+
+ /**
+ * Will never timeout, as it invokes the {@link #offer(Object)} method.
+ * Once a lock has been acquired, the
+ * {@inheritDoc}
+ */
+ public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
+ return offer(e);
+ }
+
+ /**
+ * Fair retrieval of an object in the queue.
+ * Objects are returned in the order the threads requested them.
+ * {@inheritDoc}
+ */
+ public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+ int idx = getNextPoll();
+ E result = null;
+ final ReentrantLock lock = this.locks[idx];
+ boolean error = true;
+ //acquire the global lock until we know what to do
+ lock.lock();
+ try {
+ //check to see if we have objects
+ result = items[idx].poll();
+ if (result==null && timeout>0) {
+ //the queue is empty we will wait for an object
+ ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<E>(1);
+ //add to the bottom of the wait list
+ waiters[idx].addLast(c);
+ //unlock the global lock
+ lock.unlock();
+ //wait for the specified timeout
+ if (!c.await(timeout, unit)) {
+ //if we timed out, remove ourselves from the waitlist
+ lock.lock();
+ waiters[idx].remove(c);
+ lock.unlock();
+ }
+ //return the item we received, can be null if we timed out
+ result = c.getItem();
+ } else {
+ //we have an object, release
+ lock.unlock();
+ }
+ error = false;
+ } finally {
+ if (error && lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Request an item from the queue asynchronously
+ * @return - a future pending the result from the queue poll request
+ */
+ public Future<E> pollAsync() {
+ int idx = getNextPoll();
+ Future<E> result = null;
+ final ReentrantLock lock = this.locks[idx];
+ boolean error = true;
+ //grab the global lock
+ lock.lock();
+ try {
+ //check to see if we have objects in the queue
+ E item = items[idx].poll();
+ if (item==null) {
+ //queue is empty, add ourselves as waiters
+ ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<E>(1);
+ waiters[idx].addLast(c);
+ lock.unlock();
+ //return a future that will wait for the object
+ result = new ItemFuture<E>(c);
+ } else {
+ lock.unlock();
+ //return a future with the item
+ result = new ItemFuture<E>(item);
+ }
+ error = false;
+ } finally {
+ if (error && lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean remove(Object e) {
+ for (int idx=0; idx<LOCK_COUNT; idx++) {
+ final ReentrantLock lock = this.locks[idx];
+ lock.lock();
+ try {
+ boolean result = items[idx].remove(e);
+ if (result) return result;
+ } finally {
+ lock.unlock();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size() {
+ int size = 0;
+ for (int idx=0; idx<LOCK_COUNT; idx++) {
+ size += items[idx].size();
+ }
+ return size;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<E> iterator() {
+ return new FairIterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public E poll() {
+ int idx = getNextPoll();
+ final ReentrantLock lock = this.locks[idx];
+ lock.lock();
+ try {
+ return items[idx].poll();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean contains(Object e) {
+ for (int idx=0; idx<LOCK_COUNT; idx++) {
+ boolean result = items[idx].contains(e);
+ if (result) return result;
+ }
+ return false;
+ }
+
+
+ //------------------------------------------------------------------
+ // NOT USED BY CONPOOL IMPLEMENTATION
+ //------------------------------------------------------------------
+ /**
+ * {@inheritDoc}
+ */
+ public boolean add(E e) {
+ return offer(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public int drainTo(Collection<? super E> c, int maxElements) {
+ throw new UnsupportedOperationException("int drainTo(Collection<? super E> c, int maxElements)");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public int drainTo(Collection<? super E> c) {
+ return drainTo(c,Integer.MAX_VALUE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void put(E e) throws InterruptedException {
+ offer(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int remainingCapacity() {
+ return Integer.MAX_VALUE - size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public E take() throws InterruptedException {
+ return this.poll(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean addAll(Collection<? extends E> c) {
+ Iterator<? extends E> i = c.iterator();
+ while (i.hasNext()) {
+ E e = i.next();
+ offer(e);
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public void clear() {
+ throw new UnsupportedOperationException("void clear()");
+
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public boolean containsAll(Collection<?> c) {
+ throw new UnsupportedOperationException("boolean containsAll(Collection<?> c)");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException("boolean removeAll(Collection<?> c)");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException("boolean retainAll(Collection<?> c)");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public Object[] toArray() {
+ throw new UnsupportedOperationException("Object[] toArray()");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public <T> T[] toArray(T[] a) {
+ throw new UnsupportedOperationException("<T> T[] toArray(T[] a)");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public E element() {
+ throw new UnsupportedOperationException("E element()");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public E peek() {
+ throw new UnsupportedOperationException("E peek()");
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws UnsupportedOperationException - this operation is not supported
+ */
+ public E remove() {
+ throw new UnsupportedOperationException("E remove()");
+ }
+
+
+
+ //------------------------------------------------------------------
+ // Non cancellable Future used to check and see if a connection has been made available
+ //------------------------------------------------------------------
+ protected class ItemFuture<T> implements Future<T> {
+ protected volatile T item = null;
+ protected volatile ExchangeCountDownLatch<T> latch = null;
+ protected volatile boolean canceled = false;
+
+ public ItemFuture(T item) {
+ this.item = item;
+ }
+
+ public ItemFuture(ExchangeCountDownLatch<T> latch) {
+ this.latch = latch;
+ }
+
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false; //don't allow cancel for now
+ }
+
+ public T get() throws InterruptedException, ExecutionException {
+ if (item!=null) {
+ return item;
+ } else if (latch!=null) {
+ latch.await();
+ return latch.getItem();
+ } else {
+ throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
+ }
+ }
+
+ public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ if (item!=null) {
+ return item;
+ } else if (latch!=null) {
+ boolean timedout = !latch.await(timeout, unit);
+ if (timedout) throw new TimeoutException();
+ else return latch.getItem();
+ } else {
+ throw new ExecutionException("ItemFuture incorrectly instantiated. Bug in the code?", new Exception());
+ }
+ }
+
+ public boolean isCancelled() {
+ return false;
+ }
+
+ public boolean isDone() {
+ return (item!=null || latch.getItem()!=null);
+ }
+
+ }
+
+ //------------------------------------------------------------------
+ // Count down latch that can be used to exchange information
+ //------------------------------------------------------------------
+ protected class ExchangeCountDownLatch<T> extends CountDownLatch {
+ protected volatile T item;
+ public ExchangeCountDownLatch(int i) {
+ super(i);
+ }
+ public T getItem() {
+ return item;
+ }
+ public void setItem(T item) {
+ this.item = item;
+ }
+ }
+
+ //------------------------------------------------------------------
+ // Iterator safe from concurrent modification exceptions
+ //------------------------------------------------------------------
+ protected class FairIterator implements Iterator<E> {
+ E[] elements = null;
+ int index;
+ E element = null;
+
+ public FairIterator() {
+ ArrayList<E> list = new ArrayList<E>(MultiLockFairBlockingQueue.this.size());
+ for (int idx=0; idx<LOCK_COUNT; idx++) {
+ final ReentrantLock lock = MultiLockFairBlockingQueue.this.locks[idx];
+ lock.lock();
+ try {
+ elements = (E[]) new Object[MultiLockFairBlockingQueue.this.items[idx].size()];
+ MultiLockFairBlockingQueue.this.items[idx].toArray(elements);
+
+ } finally {
+ lock.unlock();
+ }
+ }
+ index = 0;
+ elements = (E[]) new Object[list.size()];
+ list.toArray(elements);
+ }
+ public boolean hasNext() {
+ return index<elements.length;
+ }
+
+ public E next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ element = elements[index++];
+ return element;
+ }
+
+ public void remove() {
+ for (int idx=0; idx<LOCK_COUNT; idx++) {
+ final ReentrantLock lock = MultiLockFairBlockingQueue.this.locks[idx];
+ lock.lock();
+ try {
+ boolean result = MultiLockFairBlockingQueue.this.items[idx].remove(elements[index]);
+ if (result) break;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ }
+
+ }
+}
--- /dev/null
+/*
+ * 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.util.Properties;
+
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
+
+/**
+ * A list of properties that are configurable for a connection pool.
+ * The {@link DataSource} object also implements this interface so that it can be easily configured through
+ * an IoC container without having to specify a secondary object with a setter method.
+ * @author fhanik
+ *
+ */
+
+public interface PoolConfiguration {
+
+ /**
+ * JMX prefix for interceptors that register themselves with JMX
+ */
+ public static final String PKG_PREFIX = "org.apache.tomcat.jdbc.pool.interceptor.";
+
+ /**
+ * Connections that have been abandoned (timed out) wont get closed and reported up unless the number of connections in use are
+ * above the percentage defined by abandonWhenPercentageFull.
+ * The value should be between 0-100.
+ * The default value is 0, which implies that connections are eligible for
+ * closure as soon as removeAbandonedTimeout has been reached.
+ * @param percentage a value between 0 and 100 to indicate when connections that have been abandoned/timed out are considered abandoned
+ */
+ public void setAbandonWhenPercentageFull(int percentage);
+
+ /**
+ * Connections that have been abandoned (timed out) wont get closed and reported up unless the number of connections in use are
+ * above the percentage defined by abandonWhenPercentageFull.
+ * The value should be between 0-100.
+ * The default value is 0, which implies that connections are eligible for
+ * closure as soon as removeAbandonedTimeout has been reached.
+ * @return percentage - a value between 0 and 100 to indicate when connections that have been abandoned/timed out are considered abandoned
+ */
+ public int getAbandonWhenPercentageFull();
+
+ /**
+ * Returns true if a fair queue is being used by the connection pool
+ * @return true if a fair waiting queue is being used
+ */
+ public boolean isFairQueue();
+
+ /**
+ * Set to true if you wish that calls to getConnection
+ * should be treated fairly in a true FIFO fashion.
+ * This uses the {@link FairBlockingQueue} implementation for the list of the idle connections.
+ * The default value is true.
+ * This flag is required when you want to use asynchronous connection retrieval.
+ * @param fairQueue
+ */
+ public void setFairQueue(boolean fairQueue);
+
+ /**
+ * Property not used. Access is always allowed.
+ * Access can be achieved by calling unwrap on the pooled connection. see {@link javax.sql.DataSource} interface
+ * or call getConnection through reflection or cast the object as {@link javax.sql.PooledConnection}
+ * @return true
+ */
+ public boolean isAccessToUnderlyingConnectionAllowed();
+
+ /**
+ * No-op
+ * @param accessToUnderlyingConnectionAllowed parameter ignored
+ */
+ public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed);
+
+ /**
+ * The connection properties that will be sent to the JDBC driver when establishing new connections.
+ * Format of the string is [propertyName=property;] <br/>
+ * NOTE - The "user" and "password" properties will be passed explicitly, so they do not need to be included here.
+ * The default value is null.
+ */
+ public String getConnectionProperties();
+
+ /**
+ * The properties that will be passed into {@link java.sql.Driver#connect(String, Properties)} method.
+ * Username and password do not need to be stored here, they will be passed into the properties right before the connection is established.
+ * @param connectionProperties properties - Format of the string is [propertyName=property;]*
+ * Example: prop1=value1;prop2=value2
+ */
+ public void setConnectionProperties(String connectionProperties);
+
+ /**
+ * Returns the database properties that are passed into the {@link java.sql.Driver#connect(String, Properties)} method.
+ * @return database properties that are passed into the {@link java.sql.Driver#connect(String, Properties)} method.
+ */
+ public Properties getDbProperties();
+
+ /**
+ * Overrides the database properties passed into the {@link java.sql.Driver#connect(String, Properties)} method.
+ * @param dbProperties
+ */
+ public void setDbProperties(Properties dbProperties);
+
+ /**
+ * The default auto-commit state of connections created by this pool.
+ * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
+ * @return the default auto commit setting, null is Driver default.
+ */
+ public Boolean isDefaultAutoCommit();
+
+ /**
+ * The default auto-commit state of connections created by this pool.
+ * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
+ * @return the default auto commit setting, null is Driver default.
+ */
+ public Boolean getDefaultAutoCommit();
+
+ /**
+ * The default auto-commit state of connections created by this pool.
+ * If not set (null), default is JDBC driver default (If set to null then the {@link java.sql.Connection#setAutoCommit(boolean)} method will not be called.)
+ * @param defaultAutoCommit default auto commit setting, null is Driver default.
+ */
+ public void setDefaultAutoCommit(Boolean defaultAutoCommit);
+
+ /**
+ * If non null, during connection creation the method {@link java.sql.Connection#setCatalog(String)} will be called with the set value.
+ * @return the default catalog, null if not set and accepting the driver default.
+ */
+ public String getDefaultCatalog();
+
+ /**
+ * If non null, during connection creation the method {@link java.sql.Connection#setCatalog(String)} will be called with the set value.
+ * @param defaultCatalog null if not set and accepting the driver default.
+ */
+ public void setDefaultCatalog(String defaultCatalog);
+
+ /**
+ * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
+ * @return null if not set and accepting the driver default otherwise the read only value
+ */
+ public Boolean isDefaultReadOnly();
+
+ /**
+ * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
+ * @return null if not set and accepting the driver default otherwise the read only value
+ */
+ public Boolean getDefaultReadOnly();
+
+ /**
+ * If non null, during connection creation the method {@link java.sql.Connection#setReadOnly(boolean)} will be called with the set value.
+ * @param defaultReadOnly null if not set and accepting the driver default.
+ */
+ public void setDefaultReadOnly(Boolean defaultReadOnly);
+
+
+ /**
+ * Returns the default transaction isolation level. If set to {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} the method
+ * {@link java.sql.Connection#setTransactionIsolation(int)} will not be called during connection creation.
+ * @return driver transaction isolation level, or -1 {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} if not set.
+ */
+ public int getDefaultTransactionIsolation();
+
+ /**
+ * If set to {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION} the method
+ * {@link java.sql.Connection#setTransactionIsolation(int)} will not be called during connection creation. Otherwise the method
+ * will be called with the isolation level set by this property.
+ * @param defaultTransactionIsolation a value of {@link java.sql.Connection#TRANSACTION_NONE}, {@link java.sql.Connection#TRANSACTION_READ_COMMITTED},
+ * {@link java.sql.Connection#TRANSACTION_READ_UNCOMMITTED}, {@link java.sql.Connection#TRANSACTION_REPEATABLE_READ},
+ * {@link java.sql.Connection#TRANSACTION_SERIALIZABLE} or {@link DataSourceFactory#UNKNOWN_TRANSACTIONISOLATION}
+ * The last value will not be set on the connection.
+ */
+ public void setDefaultTransactionIsolation(int defaultTransactionIsolation);
+
+ /**
+ * 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
+ * @return fully qualified JDBC driver name.
+ */
+ public String getDriverClassName();
+
+ /**
+ * 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
+ * @param driverClassName a fully qualified Java class name of a {@link java.sql.Driver} implementation.
+ */
+ public void setDriverClassName(String driverClassName);
+
+ /**
+ * Returns the number of connections that will be established when the connection pool is started.
+ * Default value is 10
+ * @return number of connections to be started when pool is started
+ */
+ public int getInitialSize();
+
+ /**
+ * Set the number of connections that will be established when the connection pool is started.
+ * Default value is 10.
+ * If this value exceeds {@link #setMaxActive(int)} it will automatically be lowered.
+ * @param initialSize the number of connections to be established.
+ *
+ */
+ public void setInitialSize(int initialSize);
+
+ /**
+ * boolean flag to set if stack traces should be logged 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 false.
+ * @return true if the connection pool logs stack traces when connections are borrowed from the pool.
+ */
+ public boolean isLogAbandoned();
+
+ /**
+ * boolean flag to set if stack traces should be logged 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 false.
+ * @param logAbandoned set to true if stack traces should be recorded when {@link DataSource#getConnection()} is called.
+ */
+ public void setLogAbandoned(boolean logAbandoned);
+
+ /**
+ * The maximum number of active connections that can be allocated from this pool at the same time. The default value is 100
+ * @return the maximum number of connections used by this pool
+ */
+ public int getMaxActive();
+
+ /**
+ * The maximum number of active connections that can be allocated from this pool at the same time. The default value is 100
+ * @param maxActive hard limit for number of managed connections by this pool
+ */
+ public void setMaxActive(int maxActive);
+
+
+ /**
+ * The maximum number of connections that should be kept in the idle pool if {@link #isPoolSweeperEnabled()} returns false.
+ * If the If {@link #isPoolSweeperEnabled()} returns true, then the idle pool can grow up to {@link #getMaxActive}
+ * and will be shrunk according to {@link #getMinEvictableIdleTimeMillis()} setting.
+ * Default value is maxActive:100
+ * @return the maximum number of idle connections.
+ */
+ public int getMaxIdle();
+
+ /**
+ * The maximum number of connections that should be kept in the idle pool if {@link #isPoolSweeperEnabled()} returns false.
+ * If the If {@link #isPoolSweeperEnabled()} returns true, then the idle pool can grow up to {@link #getMaxActive}
+ * and will be shrunk according to {@link #getMinEvictableIdleTimeMillis()} setting.
+ * Default value is maxActive:100
+ * @param maxIdle the maximum size of the idle pool
+ */
+ public void setMaxIdle(int maxIdle);
+
+ /**
+ * The maximum number of milliseconds that the pool will wait (when there are no available connections and the
+ * {@link #getMaxActive} has been reached) for a connection to be returned
+ * before throwing an exception. Default value is 30000 (30 seconds)
+ * @return the number of milliseconds to wait for a connection to become available if the pool is maxed out.
+ */
+ public int getMaxWait();
+
+ /**
+ * The maximum number of milliseconds that the pool will wait (when there are no available connections and the
+ * {@link #getMaxActive} has been reached) for a connection to be returned
+ * before throwing an exception. Default value is 30000 (30 seconds)
+ * @param maxWait the maximum number of milliseconds to wait.
+ */
+ public void setMaxWait(int maxWait);
+
+ /**
+ * The minimum amount of time an object must sit idle in the pool before it is eligible for eviction.
+ * The default value is 60000 (60 seconds).
+ * @return the minimum amount of idle time in milliseconds before a connection is considered idle and eligible for eviction.
+ */
+ public int getMinEvictableIdleTimeMillis();
+
+ /**
+ * The minimum amount of time an object must sit idle in the pool before it is eligible for eviction.
+ * The default value is 60000 (60 seconds).
+ * @param minEvictableIdleTimeMillis the number of milliseconds a connection must be idle to be eligible for eviction.
+ */
+ public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis);
+
+ /**
+ * 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 and connections get closed.
+ * Default value is derived from {@link #getInitialSize()} (also see {@link #setTestWhileIdle(boolean)}
+ * The idle pool will not shrink below this value during an eviction run, hence the number of actual connections
+ * can be between {@link #getMinIdle()} and somewhere between {@link #getMaxIdle()} and {@link #getMaxActive()}
+ * @return the minimum number of idle or established connections
+ */
+ public int getMinIdle();
+
+ /**
+ * 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 and connections get closed.
+ * Default value is derived from {@link #getInitialSize()} (also see {@link #setTestWhileIdle(boolean)}
+ * The idle pool will not shrink below this value during an eviction run, hence the number of actual connections
+ * can be between {@link #getMinIdle()} and somewhere between {@link #getMaxIdle()} and {@link #getMaxActive()}
+ *
+ * @param minIdle the minimum number of idle or established connections
+ */
+ public void setMinIdle(int minIdle);
+
+ /**
+ * Returns the name of the connection pool. By default a JVM unique random name is assigned.
+ * @return the name of the pool, should be unique in a JVM
+ */
+ public String getName();
+
+ /**
+ * Sets the name of the connection pool
+ * @param name the name of the pool, should be unique in a runtime JVM
+ */
+ public void setName(String name);
+
+ /**
+ * Property not used
+ * @return unknown value
+ */
+ public int getNumTestsPerEvictionRun();
+
+ /**
+ * Property not used
+ * @param numTestsPerEvictionRun parameter ignored.
+ */
+ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun);
+
+ /**
+ * Returns the password used when establishing connections to the database.
+ * @return the password in string format
+ */
+ public String getPassword();
+
+ /**
+ * Sets the password to establish the connection with.
+ * The password will be included as a database property with the name 'password'.
+ * @param password
+ * @see #getDbProperties()
+ */
+ public void setPassword(String password);
+
+ /**
+ * @see #getName()
+ * @return name
+ */
+ public String getPoolName();
+
+ /**
+ * Returns the username used to establish the connection with
+ * @return the username used to establish the connection with
+ */
+ public String getUsername();
+
+ /**
+ * Sets the username used to establish the connection with
+ * It will also be a property called 'user' in the database properties.
+ * @param username
+ * @see #getDbProperties()
+ */
+ public void setUsername(String username);
+
+
+ /**
+ * boolean flag to remove abandoned connections if they exceed the removeAbandonedTimout.
+ * If set to true a connection is considered abandoned and eligible for removal if it has
+ * been in use longer than the {@link #getRemoveAbandonedTimeout()} and the condition for
+ * {@link #getAbandonWhenPercentageFull()} is met.
+ * Setting this to true can recover db connections from applications that fail to close a connection.
+ * See also {@link #isLogAbandoned()} The default value is false.
+ * @return true if abandoned connections can be closed and expelled out of the pool
+ */
+ public boolean isRemoveAbandoned();
+
+ /**
+ * boolean flag to remove abandoned connections if they exceed the removeAbandonedTimout.
+ * If set to true a connection is considered abandoned and eligible for removal if it has
+ * been in use longer than the {@link #getRemoveAbandonedTimeout()} and the condition for
+ * {@link #getAbandonWhenPercentageFull()} is met.
+ * Setting this to true can recover db connections from applications that fail to close a connection.
+ * See also {@link #isLogAbandoned()} The default value is false.
+ * @param removeAbandoned set to true if abandoned connections can be closed and expelled out of the pool
+ */
+ public void setRemoveAbandoned(boolean removeAbandoned);
+
+ /**
+ * The time in seconds before a connection can be considered abandoned.
+ * The timer can be reset upon queries using an interceptor.
+ * @param removeAbandonedTimeout the time in seconds before a used connection can be considered abandoned
+ * @see org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
+ */
+ public void setRemoveAbandonedTimeout(int removeAbandonedTimeout);
+
+ /**
+ * The time in seconds before a connection can be considered abandoned.
+ * The timer can be reset upon queries using an interceptor.
+ * @see org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
+ * @return the time in seconds before a used connection can be considered abandoned
+ */
+ public int getRemoveAbandonedTimeout();
+
+ /**
+ * 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 false
+ * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
+ * @return true if the connection is to be validated upon borrowing a connection from the pool
+ * @see #getValidationInterval()
+ */
+ public boolean isTestOnBorrow();
+
+ /**
+ * 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 false
+ * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
+ * @param testOnBorrow set to true if validation should take place before a connection is handed out to the application
+ * @see #getValidationInterval()
+ */
+ public void setTestOnBorrow(boolean testOnBorrow);
+
+ /**
+ * The indication of whether objects will be validated after being returned to the pool.
+ * If the 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.
+ * Default value is false
+ * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
+ * @return true if validation should take place after a connection is returned to the pool
+ * @see #getValidationInterval()
+ */
+ public boolean isTestOnReturn();
+
+ /**
+ * The indication of whether objects will be validated after being returned to the pool.
+ * If the 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.
+ * Default value is false
+ * In order to have a more efficient validation, see {@link #setValidationInterval(long)}
+ * @param testOnReturn true if validation should take place after a connection is returned to the pool
+ * @see #getValidationInterval()
+ */
+ public void setTestOnReturn(boolean testOnReturn);
+
+
+ /**
+ * Set to true if query validation should take place while the connection is idle.
+ * @return true if validation should take place during idle checks
+ * @see #setTimeBetweenEvictionRunsMillis(int)
+ */
+ public boolean isTestWhileIdle();
+
+ /**
+ * Set to true if query validation should take place while the connection is idle.
+ * @param testWhileIdle true if validation should take place during idle checks
+ * @see #setTimeBetweenEvictionRunsMillis(int)
+ */
+ public void setTestWhileIdle(boolean testWhileIdle);
+
+ /**
+ * The number of milliseconds to sleep between runs of the idle connection validation, abandoned cleaner
+ * and idle pool resizing. 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 connection and resize the idle pool.
+ * The default value is 5000 (5 seconds)
+ * @return the sleep time in between validations in milliseconds
+ */
+ public int getTimeBetweenEvictionRunsMillis();
+
+ /**
+ * The number of milliseconds to sleep between runs of the idle connection validation, abandoned cleaner
+ * and idle pool resizing. 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 connection and resize the idle pool.
+ * The default value is 5000 (5 seconds)
+ * @param timeBetweenEvictionRunsMillis the sleep time in between validations in milliseconds
+ */
+ public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis);
+
+ /**
+ * The URL used to connect to the database
+ * @return the configured URL for this connection pool
+ * @see java.sql.Driver#connect(String, Properties)
+ */
+ public String getUrl();
+
+ /**
+ * Sets the URL used to connect to the database
+ * @param url the configured URL for this connection pool
+ * @see java.sql.Driver#connect(String, Properties)
+ */
+ public void setUrl(String url);
+
+ /**
+ * The SQL query that will be used to validate connections from this
+ * pool before returning them to the caller or pool.
+ * If specified, this query does not have to return any data,
+ * it just can't throw a SQLException.
+ * The default value is null.
+ * Example values are SELECT 1(mysql),
+ * select 1 from dual(oracle),
+ * SELECT 1(MS Sql Server)
+ * @return the query used for validation or null if no validation is performed
+ */
+ public String getValidationQuery();
+
+ /**
+ * The SQL query that will be used to validate connections from this
+ * pool before returning them to the caller or pool.
+ * If specified, this query does not have to return any data,
+ * it just can't throw a SQLException.
+ * The default value is null.
+ * Example values are SELECT 1(mysql),
+ * select 1 from dual(oracle),
+ * SELECT 1(MS Sql Server)
+ * @param validationQuery the query used for validation or null if no validation is performed
+ */
+ public void setValidationQuery(String validationQuery);
+
+ /**
+ * Return the name of the optional validator class - may be null.
+ *
+ * @return the name of the optional validator class - may be null
+ */
+ public String getValidatorClassName();
+
+ /**
+ * Set the name for an optional validator class which will be used in place of test queries. If set to
+ * null, standard validation will be used.
+ *
+ * @param className the name of the optional validator class
+ */
+ public void setValidatorClassName(String className);
+
+ /**
+ * @return the optional validator object - may be null
+ */
+ public Validator getValidator();
+
+ /**
+ * 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 30000 (30 seconds).
+ * @return the validation interval in milliseconds
+ */
+ public long getValidationInterval();
+
+ /**
+ * 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 30000 (30 seconds).
+ * @param validationInterval the validation interval in milliseconds
+ */
+ public void setValidationInterval(long validationInterval);
+
+ /**
+ * A custom query to be run when a connection is first created. The default value is null.
+ * This query only runs once per connection, and that is when a new connection is established to the database.
+ * If this value is non null, it will replace the validation query during connection creation.
+ * @return the init SQL used to run against the DB or null if not set
+ */
+ public String getInitSQL();
+
+ /**
+ * A custom query to be run when a connection is first created. The default value is null.
+ * This query only runs once per connection, and that is when a new connection is established to the database.
+ * If this value is non null, it will replace the validation query during connection creation.
+ * @param initSQL the init SQL used to run against the DB or null if no query should be executed
+ */
+ public void setInitSQL(String initSQL);
+
+ /**
+ * Returns true if we should run the validation query when connecting to the database for the first time on a connection.
+ * Normally this is always set to false, unless one wants to use the validationQuery as an init query.
+ * @return true if we should run the validation query upon connect
+ */
+ public boolean isTestOnConnect();
+
+ /**
+ * Set to true if we should run the validation query when connecting to the database for the first time on a connection.
+ * Normally this is always set to false, unless one wants to use the validationQuery as an init query.
+ * Setting an {@link #setInitSQL(String)} will override this setting, as the init SQL will be used instead of the validation query
+ * @param testOnConnect set to true if we should run the validation query upon connect
+ */
+ public void setTestOnConnect(boolean testOnConnect);
+
+ /**
+ * A semicolon separated list of classnames extending {@link org.apache.tomcat.jdbc.pool.JdbcInterceptor} class.
+ * These interceptors will be inserted as an interceptor into the chain of operations on a java.sql.Connection object.
+ * Example interceptors are {@link org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer StatementFinalizer} to close all
+ * used statements during the session.
+ * {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer ResetAbandonedTimer} resets the timer upon every operation
+ * on the connection or a statement.
+ * {@link org.apache.tomcat.jdbc.pool.interceptor.ConnectionState ConnectionState} caches the auto commit, read only and catalog settings to avoid round trips to the DB.
+ * The default value is null.
+ * @return the interceptors that are used for connections.
+ * Example format: 'ConnectionState(useEquals=true,fast=yes);ResetAbandonedTimer'
+ */
+ public String getJdbcInterceptors();
+
+ /**
+ * A semicolon separated list of classnames extending {@link org.apache.tomcat.jdbc.pool.JdbcInterceptor} class.
+ * These interceptors will be inserted as an interceptor into the chain of operations on a java.sql.Connection object.
+ * Example interceptors are {@link org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer StatementFinalizer} to close all
+ * used statements during the session.
+ * {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer ResetAbandonedTimer} resets the timer upon every operation
+ * on the connection or a statement.
+ * {@link org.apache.tomcat.jdbc.pool.interceptor.ConnectionState ConnectionState} caches the auto commit, read only and catalog settings to avoid round trips to the DB.
+ * The default value is null.
+ * @param jdbcInterceptors the interceptors that are used for connections.
+ * Example format: 'ConnectionState(useEquals=true,fast=yes);ResetAbandonedTimer'
+ */
+ public void setJdbcInterceptors(String jdbcInterceptors);
+
+ /**
+ * Returns the {@link #getJdbcInterceptors()} as an array of objects with properties and the classes.
+ * @return an array of interceptors that have been configured
+ */
+ public InterceptorDefinition[] getJdbcInterceptorsAsArray();
+
+
+ /**
+ * If set to true, the connection pool creates a {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} object
+ * that can be registered with JMX to receive notifications and state about the pool.
+ * The ConnectionPool object doesn't register itself, as there is no way to keep a static non changing ObjectName across JVM restarts.
+ * @return true if the mbean object will be created upon startup.
+ */
+ public boolean isJmxEnabled();
+
+ /**
+ * If set to true, the connection pool creates a {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} object
+ * that can be registered with JMX to receive notifications and state about the pool.
+ * The ConnectionPool object doesn't register itself, as there is no way to keep a static non changing ObjectName across JVM restarts.
+ * @param jmxEnabled set to to if the mbean object should be created upon startup.
+ */
+ public void setJmxEnabled(boolean jmxEnabled);
+
+ /**
+ * Returns true if the pool sweeper is enabled for the connection pool.
+ * The pool sweeper is enabled if any settings that require async intervention in the pool are turned on
+ * <source>
+ boolean result = getTimeBetweenEvictionRunsMillis()>0;
+ result = result && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
+ result = result || (isTestWhileIdle() && getValidationQuery()!=null);
+ return result;
+ </source>
+ *
+ * @return true if a background thread is or will be enabled for this pool
+ */
+ public boolean isPoolSweeperEnabled();
+
+ /**
+ * Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> instead of
+ * <code>==</code> when comparing method names.
+ * This property does not apply to added interceptors as those are configured individually.
+ * The default value is <code>false</code>.
+ * @return true if pool uses {@link String#equals(Object)} instead of == when comparing method names on {@link java.sql.Connection} methods
+ */
+ public boolean isUseEquals();
+
+ /**
+ * Set to true if you wish the <code>ProxyConnection</code> class to use <code>String.equals</code> instead of
+ * <code>==</code> when comparing method names.
+ * This property does not apply to added interceptors as those are configured individually.
+ * The default value is <code>false</code>.
+ * @param useEquals set to true if the pool should use {@link String#equals(Object)} instead of ==
+ * when comparing method names on {@link java.sql.Connection} methods
+ */
+ public void setUseEquals(boolean useEquals);
+
+ /**
+ * Time in milliseconds to keep this connection alive even when used.
+ * When a connection is returned to the pool, the pool will check to see if the
+ * ((now - time-when-connected) > maxAge) has been reached, and if so,
+ * it closes the connection rather than returning it to the pool.
+ * The default value is 0, which implies that connections will be left open and no
+ * age check will be done upon returning the connection to the pool.
+ * This is a useful setting for database sessions that leak memory as it ensures that the session
+ * will have a finite life span.
+ * @return the time in milliseconds a connection will be open for when used
+ */
+ public long getMaxAge();
+
+ /**
+ * Time in milliseconds to keep this connection alive even when used.
+ * When a connection is returned to the pool, the pool will check to see if the
+ * ((now - time-when-connected) > maxAge) has been reached, and if so,
+ * it closes the connection rather than returning it to the pool.
+ * The default value is 0, which implies that connections will be left open and no
+ * age check will be done upon returning the connection to the pool.
+ * This is a useful setting for database sessions that leak memory as it ensures that the session
+ * will have a finite life span.
+ * @param maxAge the time in milliseconds a connection will be open for when used
+ */
+ public void setMaxAge(long maxAge);
+
+ /**
+ * Return true if a lock should be used when operations are performed on the connection object.
+ * Should be set to false unless you plan to have a background thread of your own doing idle and abandon checking
+ * such as JMX clients. If the pool sweeper is enabled, then the lock will automatically be used regardless of this setting.
+ * @return true if a lock is used.
+ */
+ public boolean getUseLock();
+
+ /**
+ * Set to true if a lock should be used when operations are performed on the connection object.
+ * Should be set to false unless you plan to have a background thread of your own doing idle and abandon checking
+ * such as JMX clients. If the pool sweeper is enabled, then the lock will automatically be used regardless of this setting.
+ * @param useLock set to true if a lock should be used on connection operations
+ */
+ public void setUseLock(boolean useLock);
+
+ /**
+ * Similar to {@link #setRemoveAbandonedTimeout(int)} but instead of treating the connection
+ * as abandoned, and potentially closing the connection, this simply logs the warning if
+ * {@link #isLogAbandoned()} returns true. If this value is equal or less than 0, no suspect
+ * checking will be performed. Suspect checking only takes place if the timeout value is larger than 0 and
+ * the connection was not abandoned or if abandon check is disabled. If a connection is suspect a WARN message gets
+ * logged and a JMX notification gets sent once.
+ * @param seconds - the amount of time in seconds that has to pass before a connection is marked suspect.
+ */
+ public void setSuspectTimeout(int seconds);
+
+ /**
+ * Returns the time in seconds to pass before a connection is marked an abanoned suspect.
+ * Any value lesser than or equal to 0 means the check is disabled.
+ * @return Returns the time in seconds to pass before a connection is marked an abanoned suspect.
+ */
+ public int getSuspectTimeout();
+
+ /**
+ * Injects a datasource that will be used to retrieve/create connections.
+ * If a data source is set, the {@link PoolConfiguration#getUrl()} and {@link PoolConfiguration#getDriverClassName()} methods are ignored
+ * and not used by the pool. If the {@link PoolConfiguration#getUsername()} and {@link PoolConfiguration#getPassword()}
+ * values are set, the method {@link javax.sql.DataSource#getConnection(String, String)} method will be called instead of the
+ * {@link javax.sql.DataSource#getConnection()} method.
+ * If the data source implements {@link javax.sql.XADataSource} the methods
+ * {@link javax.sql.XADataSource#getXAConnection()} and {@link javax.sql.XADataSource#getXAConnection(String,String)}
+ * will be invoked.
+ * @param ds the {@link javax.sql.DataSource} to be used for creating connections to be pooled.
+ */
+ public void setDataSource(Object ds);
+
+ /**
+ * Returns a datasource, if one exists that is being used to create connections.
+ * This method will return null if the pool is using a {@link java.sql.Driver}
+ * @return the {@link javax.sql.DataSource} to be used for creating connections to be pooled or null if a Driver is used.
+ */
+ public Object getDataSource();
+
+ /**
+ * Configure the connection pool to use a DataSource according to {@link PoolConfiguration#setDataSource(Object)}
+ * But instead of injecting the object, specify the JNDI location.
+ * After a successful JNDI look, the {@link PoolConfiguration#getDataSource()} will not return null.
+ * @param jndiDS -the JNDI string @TODO specify the rules here.
+ */
+ public void setDataSourceJNDI(String jndiDS);
+
+ /**
+ * Returns the JNDI string configured for data source usage.
+ * @return the JNDI string or null if not set
+ */
+ public String getDataSourceJNDI();
+
+ /**
+ * Returns true if the call {@link DataSource#getConnection(String, String) getConnection(username,password)} is
+ * allowed. This is used for when the pool is used by an application accessing multiple schemas.
+ * There is a performance impact turning this option on.
+ * @return true if {@link DataSource#getConnection(String, String) getConnection(username,password)} is honored, false if it is ignored.
+ */
+ public boolean isAlternateUsernameAllowed();
+
+ /**
+ * Set to true if the call {@link DataSource#getConnection(String, String) getConnection(username,password)} is
+ * allowed and honored.. This is used for when the pool is used by an application accessing multiple schemas.
+ * There is a performance impact turning this option on, even when not used due to username checks.
+ * @param alternateUsernameAllowed - set true if {@link DataSource#getConnection(String, String) getConnection(username,password)} is honored,
+ * false if it is to be ignored.
+ */
+ public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed);
+
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.io.IOException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * @author Filip Hanik
+ *
+ */
+public class PoolProperties implements PoolConfiguration {
+ private static final Log log = LogFactory.getLog(PoolProperties.class);
+
+ public static final int DEFAULT_MAX_ACTIVE = 100;
+
+ protected static AtomicInteger poolCounter = new AtomicInteger(0);
+ 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 = DEFAULT_MAX_ACTIVE;
+ protected int maxIdle = maxActive;
+ protected int minIdle = initialSize;
+ protected int maxWait = 30000;
+ protected String validationQuery;
+ protected String validatorClassName;
+ protected Validator validator;
+ protected boolean testOnBorrow = false;
+ protected boolean testOnReturn = false;
+ protected boolean testWhileIdle = false;
+ protected int timeBetweenEvictionRunsMillis = 5000;
+ protected int numTestsPerEvictionRun;
+ protected int minEvictableIdleTimeMillis = 60000;
+ protected final boolean accessToUnderlyingConnectionAllowed = true;
+ protected boolean removeAbandoned = false;
+ protected int removeAbandonedTimeout = 60;
+ protected boolean logAbandoned = false;
+ protected String name = "Tomcat Connection Pool["+(poolCounter.addAndGet(1))+"-"+System.identityHashCode(PoolProperties.class)+"]";
+ protected String password;
+ protected String username;
+ protected long validationInterval = 30000;
+ protected boolean jmxEnabled = true;
+ protected String initSQL;
+ protected boolean testOnConnect =false;
+ protected String jdbcInterceptors=null;
+ protected boolean fairQueue = true;
+ protected boolean useEquals = true;
+ protected int abandonWhenPercentageFull = 0;
+ protected long maxAge = 0;
+ protected boolean useLock = false;
+ protected InterceptorDefinition[] interceptors = null;
+ protected int suspectTimeout = 0;
+ protected Object dataSource = null;
+ protected String dataSourceJNDI = null;
+ protected boolean alternateUsernameAllowed = false;
+
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setAbandonWhenPercentageFull(int percentage) {
+ if (percentage<0) abandonWhenPercentageFull = 0;
+ else if (percentage>100) abandonWhenPercentageFull = 100;
+ else abandonWhenPercentageFull = percentage;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getAbandonWhenPercentageFull() {
+ return abandonWhenPercentageFull;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isFairQueue() {
+ return fairQueue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setFairQueue(boolean fairQueue) {
+ this.fairQueue = fairQueue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isAccessToUnderlyingConnectionAllowed() {
+ return accessToUnderlyingConnectionAllowed;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getConnectionProperties() {
+ return connectionProperties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Properties getDbProperties() {
+ return dbProperties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Boolean isDefaultAutoCommit() {
+ return defaultAutoCommit;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getDefaultCatalog() {
+ return defaultCatalog;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Boolean isDefaultReadOnly() {
+ return defaultReadOnly;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getDefaultTransactionIsolation() {
+ return defaultTransactionIsolation;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getInitialSize() {
+ return initialSize;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isLogAbandoned() {
+ return logAbandoned;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMaxActive() {
+ return maxActive;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMaxIdle() {
+ return maxIdle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMaxWait() {
+ return maxWait;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMinEvictableIdleTimeMillis() {
+ return minEvictableIdleTimeMillis;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getMinIdle() {
+ return minIdle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getNumTestsPerEvictionRun() {
+ return numTestsPerEvictionRun;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getPoolName() {
+ return getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isRemoveAbandoned() {
+ return removeAbandoned;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getRemoveAbandonedTimeout() {
+ return removeAbandonedTimeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isTestOnBorrow() {
+ return testOnBorrow;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isTestOnReturn() {
+ return testOnReturn;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isTestWhileIdle() {
+ return testWhileIdle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getTimeBetweenEvictionRunsMillis() {
+ return timeBetweenEvictionRunsMillis;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getUrl() {
+ return url;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getValidationQuery() {
+ return validationQuery;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getValidatorClassName() {
+ return validatorClassName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Validator getValidator() {
+ return validator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public long getValidationInterval() {
+ return validationInterval;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getInitSQL() {
+ return initSQL;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isTestOnConnect() {
+ return testOnConnect;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getJdbcInterceptors() {
+ return jdbcInterceptors;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
+ if (interceptors == null) {
+ if (jdbcInterceptors==null) {
+ interceptors = new InterceptorDefinition[0];
+ } else {
+ String[] interceptorValues = jdbcInterceptors.split(";");
+ InterceptorDefinition[] definitions = new InterceptorDefinition[interceptorValues.length];
+ for (int i=0; i<interceptorValues.length; i++) {
+ int propIndex = interceptorValues[i].indexOf("(");
+ int endIndex = interceptorValues[i].indexOf(")");
+ if (propIndex<0 || endIndex<0 || endIndex <= propIndex) {
+ definitions[i] = new InterceptorDefinition(interceptorValues[i].trim());
+ } else {
+ String name = interceptorValues[i].substring(0,propIndex).trim();
+ definitions[i] = new InterceptorDefinition(name);
+ String propsAsString = interceptorValues[i].substring(propIndex+1, interceptorValues[i].length()-1);
+ String[] props = propsAsString.split(",");
+ for (int j=0; j<props.length; j++) {
+ int pidx = props[j].indexOf("=");
+ String propName = props[j].substring(0,pidx).trim();
+ String propValue = props[j].substring(pidx+1).trim();
+ definitions[i].addProperty(new InterceptorProperty(propName,propValue));
+ }
+ }
+ }
+ interceptors = definitions;
+ }
+ }
+ return interceptors;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
+ // NOOP
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setConnectionProperties(String connectionProperties) {
+ this.connectionProperties = connectionProperties;
+ getProperties(connectionProperties, getDbProperties());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDbProperties(Properties dbProperties) {
+ this.dbProperties = dbProperties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
+ this.defaultAutoCommit = defaultAutoCommit;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDefaultCatalog(String defaultCatalog) {
+ this.defaultCatalog = defaultCatalog;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDefaultReadOnly(Boolean defaultReadOnly) {
+ this.defaultReadOnly = defaultReadOnly;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
+ this.defaultTransactionIsolation = defaultTransactionIsolation;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setDriverClassName(String driverClassName) {
+ this.driverClassName = driverClassName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setInitialSize(int initialSize) {
+ this.initialSize = initialSize;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setLogAbandoned(boolean logAbandoned) {
+ this.logAbandoned = logAbandoned;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMaxActive(int maxActive) {
+ this.maxActive = maxActive;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMaxIdle(int maxIdle) {
+ this.maxIdle = maxIdle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMaxWait(int maxWait) {
+ this.maxWait = maxWait;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
+ this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMinIdle(int minIdle) {
+ this.minIdle = minIdle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+ this.numTestsPerEvictionRun = numTestsPerEvictionRun;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setRemoveAbandoned(boolean removeAbandoned) {
+ this.removeAbandoned = removeAbandoned;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
+ this.removeAbandonedTimeout = removeAbandonedTimeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTestOnBorrow(boolean testOnBorrow) {
+ this.testOnBorrow = testOnBorrow;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTestWhileIdle(boolean testWhileIdle) {
+ this.testWhileIdle = testWhileIdle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTestOnReturn(boolean testOnReturn) {
+ this.testOnReturn = testOnReturn;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTimeBetweenEvictionRunsMillis(int
+ timeBetweenEvictionRunsMillis) {
+ this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setValidationInterval(long validationInterval) {
+ this.validationInterval = validationInterval;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setValidationQuery(String validationQuery) {
+ this.validationQuery = validationQuery;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setValidatorClassName(String className) {
+ this.validatorClassName = className;
+
+ validator = null;
+
+ if (className == null) {
+ return;
+ }
+
+ try {
+ Class<Validator> validatorClass = (Class<Validator>)Class.forName(className);
+ validator = validatorClass.newInstance();
+ } catch (ClassNotFoundException e) {
+ log.warn("The class "+className+" cannot be found.", e);
+ } catch (ClassCastException e) {
+ log.warn("The class "+className+" does not implement the Validator interface.", e);
+ } catch (InstantiationException e) {
+ log.warn("An object of class "+className+" cannot be instantiated. Make sure that "+
+ "it includes an implicit or explicit no-arg constructor.", e);
+ } catch (IllegalAccessException e) {
+ log.warn("The class "+className+" or its no-arg constructor are inaccessible.", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setInitSQL(String initSQL) {
+ this.initSQL = initSQL;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setTestOnConnect(boolean testOnConnect) {
+ this.testOnConnect = testOnConnect;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setJdbcInterceptors(String jdbcInterceptors) {
+ this.jdbcInterceptors = jdbcInterceptors;
+ this.interceptors = null;
+ }
+
+
+ public String toString() {
+ StringBuilder buf = new StringBuilder("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.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isJmxEnabled() {
+ return jmxEnabled;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setJmxEnabled(boolean jmxEnabled) {
+ this.jmxEnabled = jmxEnabled;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Boolean getDefaultAutoCommit() {
+ return defaultAutoCommit;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Boolean getDefaultReadOnly() {
+ return defaultReadOnly;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getSuspectTimeout() {
+ return this.suspectTimeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setSuspectTimeout(int seconds) {
+ this.suspectTimeout = seconds;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isPoolSweeperEnabled() {
+ boolean timer = getTimeBetweenEvictionRunsMillis()>0;
+ boolean result = timer && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
+ result = result || (timer && getSuspectTimeout()>0);
+ result = result || (timer && isTestWhileIdle() && getValidationQuery()!=null);
+ result = result || (timer && getMinEvictableIdleTimeMillis()>0);
+ return result;
+ }
+
+
+ public static class InterceptorDefinition {
+ protected String className;
+ protected Map<String,InterceptorProperty> properties = new HashMap<String,InterceptorProperty>();
+ protected volatile Class<?> clazz = null;
+ public InterceptorDefinition(String className) {
+ this.className = className;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+ public void addProperty(String name, String value) {
+ InterceptorProperty p = new InterceptorProperty(name,value);
+ addProperty(p);
+ }
+
+ public void addProperty(InterceptorProperty p) {
+ properties.put(p.getName(), p);
+ }
+
+ public Map<String,InterceptorProperty> getProperties() {
+ return properties;
+ }
+
+ public Class<? extends JdbcInterceptor> getInterceptorClass() throws ClassNotFoundException {
+ if (clazz==null) {
+ if (getClassName().indexOf(".")<0) {
+ if (log.isDebugEnabled()) {
+ log.debug("Loading interceptor class:"+PoolConfiguration.PKG_PREFIX+getClassName());
+ }
+ clazz = Class.forName(PoolConfiguration.PKG_PREFIX+getClassName(), true, this.getClass().getClassLoader());
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Loading interceptor class:"+getClassName());
+ }
+ clazz = Class.forName(getClassName(), true, this.getClass().getClassLoader());
+ }
+ }
+ return (Class<? extends JdbcInterceptor>)clazz;
+ }
+ }
+
+ public static class InterceptorProperty {
+ String name;
+ String value;
+ public InterceptorProperty(String name, String value) {
+ assert(name!=null);
+ this.name = name;
+ this.value = value;
+ }
+ public String getName() {
+ return name;
+ }
+ public String getValue() {
+ return value;
+ }
+
+ public boolean getValueAsBoolean(boolean def) {
+ if (value==null) return def;
+ if ("true".equals(value)) return true;
+ if ("false".equals(value)) return false;
+ return def;
+ }
+
+ public int getValueAsInt(int def) {
+ if (value==null) return def;
+ try {
+ int v = Integer.parseInt(value);
+ return v;
+ }catch (NumberFormatException nfe) {
+ return def;
+ }
+ }
+
+ public long getValueAsLong(long def) {
+ if (value==null) return def;
+ try {
+ return Long.parseLong(value);
+ }catch (NumberFormatException nfe) {
+ return def;
+ }
+ }
+
+ public byte getValueAsByte(byte def) {
+ if (value==null) return def;
+ try {
+ return Byte.parseByte(value);
+ }catch (NumberFormatException nfe) {
+ return def;
+ }
+ }
+
+ public short getValueAsShort(short def) {
+ if (value==null) return def;
+ try {
+ return Short.parseShort(value);
+ }catch (NumberFormatException nfe) {
+ return def;
+ }
+ }
+
+ public float getValueAsFloat(float def) {
+ if (value==null) return def;
+ try {
+ return Float.parseFloat(value);
+ }catch (NumberFormatException nfe) {
+ return def;
+ }
+ }
+
+ public double getValueAsDouble(double def) {
+ if (value==null) return def;
+ try {
+ return Double.parseDouble(value);
+ }catch (NumberFormatException nfe) {
+ return def;
+ }
+ }
+
+ public char getValueAschar(char def) {
+ if (value==null) return def;
+ try {
+ return value.charAt(0);
+ }catch (StringIndexOutOfBoundsException nfe) {
+ return def;
+ }
+ }
+
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ public boolean equals(Object o) {
+ if (o==this) return true;
+ if (o instanceof InterceptorProperty) {
+ InterceptorProperty other = (InterceptorProperty)o;
+ return other.name.equals(this.name);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean isUseEquals() {
+ return useEquals;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setUseEquals(boolean useEquals) {
+ this.useEquals = useEquals;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public long getMaxAge() {
+ return maxAge;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setMaxAge(long maxAge) {
+ this.maxAge = maxAge;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public boolean getUseLock() {
+ return useLock;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setUseLock(boolean useLock) {
+ this.useLock = useLock;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDataSource(Object ds) {
+ this.dataSource = ds;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getDataSource() {
+ return dataSource;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDataSourceJNDI(String jndiDS) {
+ this.dataSourceJNDI = jndiDS;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getDataSourceJNDI() {
+ return this.dataSourceJNDI;
+ }
+
+
+ public static Properties getProperties(String propText, Properties props) {
+ if (props==null) props = new Properties();
+ if (propText != null) {
+ try {
+ props.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
+ }catch (IOException x) {
+ throw new RuntimeException(x);
+ }
+ }
+ return props;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isAlternateUsernameAllowed() {
+ return alternateUsernameAllowed;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
+ this.alternateUsernameAllowed = alternateUsernameAllowed;
+ }
+
+}
--- /dev/null
+/*
+ * 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.util.Properties;
+
+/**
+ *
+ * @author fhanik
+ *
+ */
+public class PoolUtilities {
+
+ public static final String PROP_USER = "user";
+
+ public static final String PROP_PASSWORD = "password";
+
+ public static Properties clone(Properties p) {
+ Properties c = new Properties();
+ c.putAll(p);
+ return c;
+ }
+
+ public static Properties cloneWithoutPassword(Properties p) {
+ Properties result = clone(p);
+ result.remove(PROP_PASSWORD);
+ return result;
+ }
+}
--- /dev/null
+/*
+ * 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.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Represents a pooled connection
+ * and holds a reference to the {@link java.sql.Connection} object
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class PooledConnection {
+ /**
+ * Logger
+ */
+ private static final Log log = LogFactory.getLog(PooledConnection.class);
+
+ public static final String PROP_USER = PoolUtilities.PROP_USER;
+
+ public static final String PROP_PASSWORD = PoolUtilities.PROP_PASSWORD;
+
+ /**
+ * Validate when connection is borrowed flag
+ */
+ public static final int VALIDATE_BORROW = 1;
+ /**
+ * Validate when connection is returned flag
+ */
+ public static final int VALIDATE_RETURN = 2;
+ /**
+ * Validate when connection is idle flag
+ */
+ public static final int VALIDATE_IDLE = 3;
+ /**
+ * Validate when connection is initialized flag
+ */
+ public static final int VALIDATE_INIT = 4;
+ /**
+ * The properties for the connection pool
+ */
+ protected PoolConfiguration poolProperties;
+ /**
+ * The underlying database connection
+ */
+ private volatile java.sql.Connection connection;
+
+ /**
+ * If using a XAConnection underneath.
+ */
+ protected volatile javax.sql.XAConnection xaConnection;
+ /**
+ * When we track abandon traces, this string holds the thread dump
+ */
+ private String abandonTrace = null;
+ /**
+ * Timestamp the connection was last 'touched' by the pool
+ */
+ private volatile long timestamp;
+ /**
+ * Lock for this connection only
+ */
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
+ /**
+ * Set to true if this connection has been discarded by the pool
+ */
+ private volatile boolean discarded = false;
+ /**
+ * The Timestamp when the last time the connect() method was called successfully
+ */
+ private volatile long lastConnected = -1;
+ /**
+ * timestamp to keep track of validation intervals
+ */
+ private volatile long lastValidated = System.currentTimeMillis();
+ /**
+ * The parent
+ */
+ protected ConnectionPool parent;
+
+ private HashMap<Object, Object> attributes = new HashMap<Object, Object>();
+
+ /**
+ * Weak reference to cache the list of interceptors for this connection
+ * so that we don't create a new list of interceptors each time we borrow
+ * the connection
+ */
+ private volatile JdbcInterceptor handler = null;
+
+ private AtomicBoolean released = new AtomicBoolean(false);
+
+ private volatile boolean suspect = false;
+
+ private java.sql.Driver driver = null;
+
+ /**
+ * Constructor
+ * @param prop - pool properties
+ * @param parent - the parent connection pool
+ */
+ public PooledConnection(PoolConfiguration prop, ConnectionPool parent) {
+ poolProperties = prop;
+ this.parent = parent;
+ }
+
+ public boolean checkUser(String username, String password) {
+ if (!getPoolProperties().isAlternateUsernameAllowed()) return true;
+
+ if (username==null) username = poolProperties.getUsername();
+ if (password==null) password = poolProperties.getPassword();
+
+ String storedUsr = (String)getAttributes().get(PROP_USER);
+ String storedPwd = (String)getAttributes().get(PROP_PASSWORD);
+
+ boolean result = (username==null && storedUsr==null);
+ result = (result || (username!=null && username.equals(storedUsr)));
+
+ result = result && ((password==null && storedPwd==null) || (password!=null && password.equals(storedPwd)));
+
+ if (username==null) getAttributes().remove(PROP_USER); else getAttributes().put(PROP_USER, username);
+ if (password==null) getAttributes().remove(PROP_PASSWORD); else getAttributes().put(PROP_PASSWORD, password);
+
+ return result;
+ }
+
+ /**
+ * Connects the underlying connection to the database.
+ * @throws SQLException if the method {@link #release()} has been called.
+ * @throws SQLException if driver instantiation fails
+ * @throws SQLException if a call to {@link java.sql.Driver#connect(String, java.util.Properties)} fails.
+ * @throws SQLException if default properties are configured and a call to
+ * {@link java.sql.Connection#setAutoCommit(boolean)}, {@link java.sql.Connection#setCatalog(String)},
+ * {@link java.sql.Connection#setTransactionIsolation(int)} or {@link java.sql.Connection#setReadOnly(boolean)} fails.
+ */
+ public void connect() throws SQLException {
+ if (released.get()) throw new SQLException("A connection once released, can't be reestablished.");
+ if (connection != null) {
+ try {
+ this.disconnect(false);
+ } catch (Exception x) {
+ log.debug("Unable to disconnect previous connection.", x);
+ } //catch
+ } //end if
+ if (poolProperties.getDataSource()==null && poolProperties.getDataSourceJNDI()!=null) {
+ //TODO lookup JNDI name
+ }
+
+ if (poolProperties.getDataSource()!=null) {
+ connectUsingDataSource();
+ } else {
+ connectUsingDriver();
+ }
+
+ //set up the default state, unless we expect the interceptor to do it
+ if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0) {
+ if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
+ 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());
+ }
+ this.discarded = false;
+ this.lastConnected = System.currentTimeMillis();
+ }
+
+ protected void connectUsingDataSource() throws SQLException {
+ String usr = null;
+ String pwd = null;
+ if (getAttributes().containsKey(PROP_USER)) {
+ usr = (String) getAttributes().get(PROP_USER);
+ } else {
+ usr = poolProperties.getUsername();
+ getAttributes().put(PROP_USER, usr);
+ }
+ if (getAttributes().containsKey(PROP_PASSWORD)) {
+ pwd = (String) getAttributes().get(PROP_PASSWORD);
+ } else {
+ pwd = poolProperties.getPassword();
+ getAttributes().put(PROP_PASSWORD, pwd);
+ }
+ if (poolProperties.getDataSource() instanceof javax.sql.XADataSource) {
+ javax.sql.XADataSource xds = (javax.sql.XADataSource)poolProperties.getDataSource();
+ if (usr!=null && pwd!=null) {
+ xaConnection = xds.getXAConnection(usr, pwd);
+ connection = xaConnection.getConnection();
+ } else {
+ xaConnection = xds.getXAConnection();
+ connection = xaConnection.getConnection();
+ }
+ } else if (poolProperties.getDataSource() instanceof javax.sql.DataSource){
+ javax.sql.DataSource ds = (javax.sql.DataSource)poolProperties.getDataSource();
+ if (usr!=null && pwd!=null) {
+ connection = ds.getConnection(usr, pwd);
+ } else {
+ connection = ds.getConnection();
+ }
+ } else if (poolProperties.getDataSource() instanceof javax.sql.ConnectionPoolDataSource){
+ javax.sql.ConnectionPoolDataSource ds = (javax.sql.ConnectionPoolDataSource)poolProperties.getDataSource();
+ if (usr!=null && pwd!=null) {
+ connection = ds.getPooledConnection(usr, pwd).getConnection();
+ } else {
+ connection = ds.getPooledConnection().getConnection();
+ }
+ } else {
+ throw new SQLException("DataSource is of unknown class:"+(poolProperties.getDataSource()!=null?poolProperties.getDataSource().getClass():"null"));
+ }
+ }
+ protected void connectUsingDriver() throws SQLException {
+
+ try {
+ if (driver==null)
+ driver = (java.sql.Driver) Class.forName(poolProperties.getDriverClassName(),
+ true, PooledConnection.class.getClassLoader()
+ ).newInstance();
+ } catch (java.lang.Exception cn) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to instantiate JDBC driver.", cn);
+ }
+ SQLException ex = new SQLException(cn.getMessage());
+ ex.initCause(cn);
+ throw ex;
+ }
+ String driverURL = poolProperties.getUrl();
+ String usr = null;
+ String pwd = null;
+ if (getAttributes().containsKey(PROP_USER)) {
+ usr = (String) getAttributes().get(PROP_USER);
+ } else {
+ usr = poolProperties.getUsername();
+ getAttributes().put(PROP_USER, usr);
+ }
+ if (getAttributes().containsKey(PROP_PASSWORD)) {
+ pwd = (String) getAttributes().get(PROP_PASSWORD);
+ } else {
+ pwd = poolProperties.getPassword();
+ getAttributes().put(PROP_PASSWORD, pwd);
+ }
+ Properties properties = PoolUtilities.clone(poolProperties.getDbProperties());
+ if (usr != null) properties.setProperty(PROP_USER, usr);
+ if (pwd != null) properties.setProperty(PROP_PASSWORD, pwd);
+
+ try {
+ connection = connection = driver.connect(driverURL, properties);
+ } catch (Exception x) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to connect to database.", x);
+ }
+ if (parent.jmxPool!=null) {
+ parent.jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_CONNECT,
+ ConnectionPool.getStackTrace(x));
+ }
+ if (x instanceof SQLException) {
+ throw (SQLException)x;
+ } else {
+ SQLException ex = new SQLException(x.getMessage());
+ ex.initCause(x);
+ throw ex;
+ }
+ }
+ if (connection==null) {
+ throw new SQLException("Driver:"+driver+" returned null for URL:"+driverURL);
+ }
+ }
+
+ /**
+ *
+ * @return true if connect() was called successfully and disconnect has not yet been called
+ */
+ public boolean isInitialized() {
+ return connection!=null;
+ }
+
+ /**
+ * Issues a call to {@link #disconnect(boolean)} with the argument false followed by a call to
+ * {@link #connect()}
+ * @throws SQLException if the call to {@link #connect()} fails.
+ */
+ public void reconnect() throws SQLException {
+ this.disconnect(false);
+ this.connect();
+ } //reconnect
+
+ /**
+ * Disconnects the connection. All exceptions are logged using debug level.
+ * @param finalize if set to true, a call to {@link ConnectionPool#finalize(PooledConnection)} is called.
+ */
+ private void disconnect(boolean finalize) {
+ if (isDiscarded()) {
+ return;
+ }
+ setDiscarded(true);
+ if (connection != null) {
+ try {
+ parent.disconnectEvent(this, finalize);
+ if (xaConnection == null) {
+ connection.close();
+ } else {
+ xaConnection.close();
+ }
+ }catch (Exception ignore) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to close underlying SQL connection",ignore);
+ }
+ }
+ }
+ connection = null;
+ xaConnection = null;
+ lastConnected = -1;
+ if (finalize) parent.finalize(this);
+ }
+
+
+//============================================================================
+//
+//============================================================================
+
+ /**
+ * Returns abandon timeout in milliseconds
+ * @return abandon timeout in milliseconds
+ */
+ public long getAbandonTimeout() {
+ if (poolProperties.getRemoveAbandonedTimeout() <= 0) {
+ return Long.MAX_VALUE;
+ } else {
+ return poolProperties.getRemoveAbandonedTimeout()*1000;
+ } //end if
+ }
+
+ /**
+ * Returns true if the connection pool is configured
+ * to do validation for a certain action.
+ * @param action
+ * @return
+ */
+ private 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);
+ }
+
+ /**
+ * Validates a connection.
+ * @param validateAction the action used. One of {@link #VALIDATE_BORROW}, {@link #VALIDATE_IDLE},
+ * {@link #VALIDATE_INIT} or {@link #VALIDATE_RETURN}
+ * @param sql the SQL to be used during validation. If the {@link PoolConfiguration#setInitSQL(String)} has been called with a non null
+ * value and the action is {@link #VALIDATE_INIT} the init SQL will be used for validation.
+ *
+ * @return true if the connection was validated successfully. It returns true even if validation was not performed, such as when
+ * {@link PoolConfiguration#setValidationInterval(long)} has been called with a positive value.
+ * <p>
+ * false if the validation failed. The caller should close the connection if false is returned since a session could have been left in
+ * an unknown state during initialization.
+ */
+ public boolean validate(int validateAction,String sql) {
+ if (this.isDiscarded()) {
+ return false;
+ }
+
+ if (!doValidate(validateAction)) {
+ //no validation required, no init sql and props not set
+ return true;
+ }
+
+ //Don't bother validating if already have recently enough
+ long now = System.currentTimeMillis();
+ if (validateAction!=VALIDATE_INIT &&
+ poolProperties.getValidationInterval() > 0 &&
+ (now - this.lastValidated) <
+ poolProperties.getValidationInterval()) {
+ return true;
+ }
+
+ if (poolProperties.getValidator() != null) {
+ if (poolProperties.getValidator().validate(connection, validateAction)) {
+ this.lastValidated = now;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ String query = sql;
+
+ if (validateAction == VALIDATE_INIT && poolProperties.getInitSQL() != null) {
+ query = poolProperties.getInitSQL();
+ }
+
+ if (query == null) {
+ query = poolProperties.getValidationQuery();
+ }
+
+ Statement stmt = null;
+ try {
+ stmt = connection.createStatement();
+ stmt.execute(query);
+ stmt.close();
+ this.lastValidated = now;
+ return true;
+ } catch (Exception ignore) {
+ if (log.isDebugEnabled())
+ log.debug("Unable to validate object:",ignore);
+ if (stmt!=null)
+ try { stmt.close();} catch (Exception ignore2){/*NOOP*/}
+ }
+ return false;
+ } //validate
+
+ /**
+ * The time limit for how long the object
+ * can remain unused before it is released
+ * @return {@link PoolConfiguration#getMinEvictableIdleTimeMillis()}
+ */
+ public long getReleaseTime() {
+ return this.poolProperties.getMinEvictableIdleTimeMillis();
+ }
+
+ /**
+ * This method is called if (Now - timeCheckedIn > getReleaseTime())
+ * This method disconnects the connection, logs an error in debug mode if it happens
+ * then sets the {@link #released} flag to false. Any attempts to connect this cached object again
+ * will fail per {@link #connect()}
+ * The connection pool uses the atomic return value to decrement the pool size counter.
+ * @return true if this is the first time this method has been called. false if this method has been called before.
+ */
+ public boolean release() {
+ try {
+ disconnect(true);
+ } catch (Exception x) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to close SQL connection",x);
+ }
+ }
+ return released.compareAndSet(false, true);
+
+ }
+
+ /**
+ * The pool will set the stack trace when it is check out and
+ * checked in
+ * @param trace the stack trace for this connection
+ */
+
+ public void setStackTrace(String trace) {
+ abandonTrace = trace;
+ }
+
+ /**
+ * Returns the stack trace from when this connection was borrowed. Can return null if no stack trace was set.
+ * @return the stack trace or null of no trace was set
+ */
+ public String getStackTrace() {
+ return abandonTrace;
+ }
+
+ /**
+ * Sets a timestamp on this connection. A timestamp usually means that some operation
+ * performed successfully.
+ * @param timestamp the timestamp as defined by {@link System#currentTimeMillis()}
+ */
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ setSuspect(false);
+ }
+
+
+ public boolean isSuspect() {
+ return suspect;
+ }
+
+ public void setSuspect(boolean suspect) {
+ this.suspect = suspect;
+ }
+
+ /**
+ * An interceptor can call this method with the value true, and the connection will be closed when it is returned to the pool.
+ * @param discarded - only valid value is true
+ * @throws IllegalStateException if this method is called with the value false and the value true has already been set.
+ */
+ 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;
+ }
+
+ /**
+ * Set the timestamp the connection was last validated.
+ * This flag is used to keep track when we are using a {@link PoolConfiguration#setValidationInterval(long) validation-interval}.
+ * @param lastValidated a timestamp as defined by {@link System#currentTimeMillis()}
+ */
+ public void setLastValidated(long lastValidated) {
+ this.lastValidated = lastValidated;
+ }
+
+ /**
+ * Sets the pool configuration for this connection and connection pool.
+ * Object is shared with the {@link ConnectionPool}
+ * @param poolProperties
+ */
+ public void setPoolProperties(PoolConfiguration poolProperties) {
+ this.poolProperties = poolProperties;
+ }
+
+ /**
+ * Return the timestamps of last pool action. Timestamps are typically set when connections
+ * are borrowed from the pool. It is used to keep track of {@link PoolConfiguration#setRemoveAbandonedTimeout(int) abandon-timeouts}.
+ * This timestamp can also be reset by the {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer#invoke(Object, java.lang.reflect.Method, Object[])}
+ * @return the timestamp of the last pool action as defined by {@link System#currentTimeMillis()}
+ */
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ /**
+ * Returns the discarded flag.
+ * @return the discarded flag. If the value is true,
+ * either {@link #disconnect(boolean)} has been called or it will be called when the connection is returned to the pool.
+ */
+ public boolean isDiscarded() {
+ return discarded;
+ }
+
+ /**
+ * Returns the timestamp of the last successful validation query execution.
+ * @return the timestamp of the last successful validation query execution as defined by {@link System#currentTimeMillis()}
+ */
+ public long getLastValidated() {
+ return lastValidated;
+ }
+
+ /**
+ * Returns the configuration for this connection and pool
+ * @return the configuration for this connection and pool
+ */
+ public PoolConfiguration getPoolProperties() {
+ return poolProperties;
+ }
+
+ /**
+ * Locks the connection only if either {@link PoolConfiguration#isPoolSweeperEnabled()} or
+ * {@link PoolConfiguration#getUseLock()} return true. The per connection lock ensures thread safety is
+ * multiple threads are performing operations on the connection.
+ * Otherwise this is a noop for performance
+ */
+ public void lock() {
+ if (poolProperties.getUseLock() || this.poolProperties.isPoolSweeperEnabled()) {
+ //optimized, only use a lock when there is concurrency
+ lock.writeLock().lock();
+ }
+ }
+
+ /**
+ * Unlocks the connection only if the sweeper is enabled
+ * Otherwise this is a noop for performance
+ */
+ public void unlock() {
+ if (poolProperties.getUseLock() || this.poolProperties.isPoolSweeperEnabled()) {
+ //optimized, only use a lock when there is concurrency
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Returns the underlying connection
+ * @return the underlying JDBC connection as it was returned from the JDBC driver
+ * @see javax.sql.PooledConnection#getConnection()
+ */
+ public java.sql.Connection getConnection() {
+ return this.connection;
+ }
+
+ /**
+ * Returns the underlying XA connection
+ * @return the underlying XA connection as it was returned from the Datasource
+ */
+ public javax.sql.XAConnection getXAConnection() {
+ return this.xaConnection;
+ }
+
+
+ /**
+ * Returns the timestamp of when the connection was last connected to the database.
+ * ie, a successful call to {@link java.sql.Driver#connect(String, java.util.Properties)}.
+ * @return the timestamp when this connection was created as defined by {@link System#currentTimeMillis()}
+ */
+ public long getLastConnected() {
+ return lastConnected;
+ }
+
+ /**
+ * Returns the first handler in the interceptor chain
+ * @return the first interceptor for this connection
+ */
+ public JdbcInterceptor getHandler() {
+ return handler;
+ }
+
+ public void setHandler(JdbcInterceptor handler) {
+ if (this.handler!=null && this.handler!=handler) {
+ JdbcInterceptor interceptor = this.handler;
+ while (interceptor!=null) {
+ interceptor.reset(null, null);
+ interceptor = interceptor.getNext();
+ }//while
+ }//end if
+ this.handler = handler;
+ }
+
+ @Override
+ public String toString() {
+ return "PooledConnection["+(connection!=null?connection.toString():"null")+"]";
+ }
+
+ /**
+ * Returns true if this connection has been released and wont be reused.
+ * @return true if the method {@link #release()} has been called
+ */
+ public boolean isReleased() {
+ return released.get();
+ }
+
+ public HashMap<Object,Object> getAttributes() {
+ return attributes;
+ }
+
+}
--- /dev/null
+/*
+ * 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.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+
+import javax.sql.XAConnection;
+/**
+ * A ProxyConnection object is the bottom most interceptor that wraps an object of type
+ * {@link PooledConnection}. The ProxyConnection intercepts three methods:
+ * <ul>
+ * <li>{@link java.sql.Connection#close()} - returns the connection to the pool. May be called multiple times.</li>
+ * <li>{@link java.lang.Object#toString()} - returns a custom string for this object</li>
+ * <li>{@link javax.sql.PooledConnection#getConnection()} - returns the underlying connection</li>
+ * </ul>
+ * By default method comparisons is done on a String reference level, unless the {@link PoolConfiguration#setUseEquals(boolean)} has been called
+ * with a <code>true</code> argument.
+ * @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, boolean useEquals) throws SQLException {
+ pool = parent;
+ connection = con;
+ setUseEquals(useEquals);
+ }
+
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ this.pool = parent;
+ this.connection = con;
+ }
+
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ if (iface == XAConnection.class && connection.getXAConnection()!=null) {
+ return true;
+ } else {
+ return (iface.isInstance(connection.getConnection()));
+ }
+ }
+
+
+ public Object unwrap(Class<?> iface) throws SQLException {
+ if (iface == PooledConnection.class) {
+ return connection;
+ }else if (iface == XAConnection.class) {
+ return connection.getXAConnection();
+ } else if (isWrapperFor(iface)) {
+ return connection.getConnection();
+ } else {
+ throw new SQLException("Not a wrapper of "+iface.getName());
+ }
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (compare(ISCLOSED_VAL,method)) {
+ return Boolean.valueOf(isClosed());
+ }
+ if (compare(CLOSE_VAL,method)) {
+ if (isClosed()) return null; //noop for already closed.
+ PooledConnection poolc = this.connection;
+ this.connection = null;
+ pool.returnConnection(poolc);
+ return null;
+ } else if (compare(TOSTRING_VAL,method)) {
+ return this.toString();
+ } else if (compare(GETCONNECTION_VAL,method) && connection!=null) {
+ return connection.getConnection();
+ } else if (method.getDeclaringClass().equals(XAConnection.class)) {
+ try {
+ return method.invoke(connection.getXAConnection(),args);
+ }catch (Throwable t) {
+ if (t instanceof InvocationTargetException) {
+ InvocationTargetException it = (InvocationTargetException)t;
+ throw it.getCause()!=null?it.getCause():it;
+ } else {
+ throw t;
+ }
+ }
+ }
+ if (isClosed()) throw new SQLException("Connection has already been closed.");
+ if (compare(UNWRAP_VAL,method)) {
+ return unwrap((Class<?>)args[0]);
+ } else if (compare(ISWRAPPERFOR_VAL,method)) {
+ return this.isWrapperFor((Class<?>)args[0]);
+ }
+ try {
+ return method.invoke(connection.getConnection(),args);
+ }catch (Throwable t) {
+ if (t instanceof InvocationTargetException) {
+ InvocationTargetException it = (InvocationTargetException)t;
+ throw it.getCause()!=null?it.getCause():it;
+ } else {
+ throw t;
+ }
+ }
+ }
+
+ public boolean isClosed() {
+ return connection==null || connection.isDiscarded();
+ }
+
+ public PooledConnection getDelegateConnection() {
+ return connection;
+ }
+
+ public ConnectionPool getParentPool() {
+ return pool;
+ }
+
+ @Override
+ public String toString() {
+ return "ProxyConnection["+(connection!=null?connection.toString():"null")+"]";
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+
+/**
+ * Interface to be implemented by custom validator classes.
+ *
+ * @author mpassell
+ */
+public interface Validator {
+ /**
+ * Validate a connection and return a boolean to indicate if it's valid.
+ *
+ * @param connection the Connection object to test
+ * @param validateAction the action used. One of {@link PooledConnection#VALIDATE_BORROW},
+ * {@link PooledConnection#VALIDATE_IDLE}, {@link PooledConnection#VALIDATE_INIT} or
+ * {@link PooledConnection#VALIDATE_RETURN}
+ * @return true if the connection is valid
+ */
+ public boolean validate(Connection connection, int validateAction);
+}
--- /dev/null
+/*
+ * 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;
+
+public class XADataSource extends DataSource implements javax.sql.XADataSource {
+
+ /**
+ * Constructor for reflection only. A default set of pool properties will be created.
+ */
+ public XADataSource() {
+ super();
+ }
+
+ /**
+ * Constructs a DataSource object wrapping a connection
+ * @param poolProperties
+ */
+ public XADataSource(PoolConfiguration poolProperties) {
+ super(poolProperties);
+ }
+
+}
--- /dev/null
+/*
+ * 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.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+/**
+ * Abstraction interceptor. This component intercepts all calls to create some type of SQL statement.
+ * By extending this class, one can intercept queries and update statements by overriding the {@link #createStatement(Object, Method, Object[], Object, long)}
+ * method.
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public abstract class AbstractCreateStatementInterceptor extends JdbcInterceptor {
+ protected static final String CREATE_STATEMENT = "createStatement";
+ protected static final int CREATE_STATEMENT_IDX = 0;
+ protected static final String PREPARE_STATEMENT = "prepareStatement";
+ protected static final int PREPARE_STATEMENT_IDX = 1;
+ protected static final String PREPARE_CALL = "prepareCall";
+ protected static final int PREPARE_CALL_IDX = 2;
+
+ protected static final String[] STATEMENT_TYPES = {CREATE_STATEMENT, PREPARE_STATEMENT, PREPARE_CALL};
+ protected static final int STATEMENT_TYPE_COUNT = STATEMENT_TYPES.length;
+
+ protected static final String EXECUTE = "execute";
+ protected static final String EXECUTE_QUERY = "executeQuery";
+ protected static final String EXECUTE_UPDATE = "executeUpdate";
+ protected static final String EXECUTE_BATCH = "executeBatch";
+
+ protected static final String[] EXECUTE_TYPES = {EXECUTE, EXECUTE_QUERY, EXECUTE_UPDATE, EXECUTE_BATCH};
+
+ public AbstractCreateStatementInterceptor() {
+ super();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (compare(CLOSE_VAL,method)) {
+ closeInvoked();
+ return super.invoke(proxy, method, args);
+ } else {
+ boolean process = false;
+ process = isStatement(method, process);
+ if (process) {
+ long start = System.currentTimeMillis();
+ Object statement = super.invoke(proxy,method,args);
+ long delta = System.currentTimeMillis() - start;
+ return createStatement(proxy,method,args,statement, delta);
+ } else {
+ return super.invoke(proxy,method,args);
+ }
+ }
+ }
+
+ /**
+ * This method will be invoked after a successful statement creation. This method can choose to return a wrapper
+ * around the statement or return the statement itself.
+ * If this method returns a wrapper then it should return a wrapper object that implements one of the following interfaces.
+ * {@link java.sql.Statement}, {@link java.sql.PreparedStatement} or {@link java.sql.CallableStatement}
+ * @param proxy the actual proxy object
+ * @param method the method that was called. It will be one of the methods defined in {@link #STATEMENT_TYPES}
+ * @param args the arguments to the method
+ * @param statement the statement that the underlying connection created
+ * @return a {@link java.sql.Statement} object
+ */
+ public abstract Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time);
+
+ /**
+ * Method invoked when the operation {@link java.sql.Connection#close()} is invoked.
+ */
+ public abstract void closeInvoked();
+
+ /**
+ * Returns true if the method that is being invoked matches one of the statement types.
+ *
+ * @param method the method being invoked on the proxy
+ * @param process boolean result used for recursion
+ * @return returns true if the method name matched
+ */
+ protected boolean isStatement(Method method, boolean process){
+ return process(STATEMENT_TYPES, method, process);
+ }
+
+ /**
+ * Returns true if the method that is being invoked matches one of the execute types.
+ *
+ * @param method the method being invoked on the proxy
+ * @param process boolean result used for recursion
+ * @return returns true if the method name matched
+ */
+ protected boolean isExecute(Method method, boolean process){
+ return process(EXECUTE_TYPES, method, process);
+ }
+
+ /*
+ * Returns true if the method that is being invoked matches one of the method names passed in
+ * @param names list of method names that we want to intercept
+ * @param method the method being invoked on the proxy
+ * @param process boolean result used for recursion
+ * @return returns true if the method name matched
+ */
+ protected boolean process(String[] names, Method method, boolean process) {
+ final String name = method.getName();
+ for (int i=0; (!process) && i<names.length; i++) {
+ process = compare(names[i],name);
+ }
+ return process;
+ }
+
+ /**
+ * no-op for this interceptor. no state is stored.
+ */
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ // NOOP
+ }
+}
--- /dev/null
+/*
+ * 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.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+/**
+ * Abstract class that wraps statements and intercepts query executions.
+ * @author fhanik
+ *
+ */
+public abstract class AbstractQueryReport extends AbstractCreateStatementInterceptor {
+ //logger
+ private static final Log log = LogFactory.getLog(AbstractQueryReport.class);
+
+ /**
+ * The threshold in milliseconds. If the query is faster than this, we don't measure it
+ */
+ protected long threshold = 1000; //don't report queries less than this
+
+ /**
+ * the constructors that are used to create statement proxies
+ */
+ protected static final Constructor<?>[] constructors =
+ new Constructor[AbstractCreateStatementInterceptor.STATEMENT_TYPE_COUNT];
+
+
+ public AbstractQueryReport() {
+ super();
+ }
+
+ /**
+ * Invoked when prepareStatement has been called and completed.
+ * @param sql - the string used to prepare the statement with
+ * @param time - the time it took to invoke prepare
+ */
+ protected abstract void prepareStatement(String sql, long time);
+
+ /**
+ * Invoked when prepareCall has been called and completed.
+ * @param query - the string used to prepare the statement with
+ * @param time - the time it took to invoke prepare
+ */
+ protected abstract void prepareCall(String query, long time);
+
+ /**
+ * Invoked when a query execution, a call to execute/executeQuery or executeBatch failed.
+ * @param query the query that was executed and failed
+ * @param args the arguments to the execution
+ * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
+ * @param start the time the query execution started
+ * @param t the exception that happened
+ * @return - the SQL that was executed or the string "batch" if it was a batch execution
+ */
+ protected String reportFailedQuery(String query, Object[] args, final String name, long start, Throwable t) {
+ //extract the query string
+ String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query;
+ //if we do batch execution, then we name the query 'batch'
+ if (sql==null && compare(EXECUTE_BATCH,name)) {
+ sql = "batch";
+ }
+ return sql;
+ }
+
+ /**
+ * Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded and was within the timing threshold
+ * @param query the query that was executed and failed
+ * @param args the arguments to the execution
+ * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
+ * @param start the time the query execution started
+ * @param delta the time the execution took
+ * @return - the SQL that was executed or the string "batch" if it was a batch execution
+ */
+ protected String reportQuery(String query, Object[] args, final String name, long start, long delta) {
+ //extract the query string
+ String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query;
+ //if we do batch execution, then we name the query 'batch'
+ if (sql==null && compare(EXECUTE_BATCH,name)) {
+ sql = "batch";
+ }
+ return sql;
+ }
+
+ /**
+ * Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded and was exceeded the timing threshold
+ * @param query the query that was executed and failed
+ * @param args the arguments to the execution
+ * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
+ * @param start the time the query execution started
+ * @param delta the time the execution took
+ * @return - the SQL that was executed or the string "batch" if it was a batch execution
+ */
+ protected String reportSlowQuery(String query, Object[] args, final String name, long start, long delta) {
+ //extract the query string
+ String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query;
+ //if we do batch execution, then we name the query 'batch'
+ if (sql==null && compare(EXECUTE_BATCH,name)) {
+ sql = "batch";
+ }
+ return sql;
+ }
+
+ /**
+ * returns the query measure threshold.
+ * This value is in milliseconds. If the query is faster than this threshold than it wont be accounted for
+ * @return the threshhold in milliseconds
+ */
+ public long getThreshold() {
+ return threshold;
+ }
+
+ /**
+ * Sets the query measurement threshold. The value is in milliseconds.
+ * If the query goes faster than this threshold it will not be recorded.
+ * @param threshold set to -1 to record every query. Value is in milliseconds.
+ */
+ public void setThreshold(long threshold) {
+ this.threshold = threshold;
+ }
+
+ /**
+ * Creates a constructor for a proxy class, if one doesn't already exist
+ * @param idx - the index of the constructor
+ * @param clazz - the interface that the proxy will implement
+ * @return - returns a constructor used to create new instances
+ * @throws NoSuchMethodException
+ */
+ protected Constructor<?> getConstructor(int idx, Class<?> clazz) throws NoSuchMethodException {
+ if (constructors[idx]==null) {
+ Class<?> proxyClass = Proxy.getProxyClass(SlowQueryReport.class.getClassLoader(), new Class[] {clazz});
+ constructors[idx] = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+ }
+ return constructors[idx];
+ }
+
+ /**
+ * Creates a statement interceptor to monitor query response times
+ */
+ @Override
+ public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
+ try {
+ Object result = null;
+ String name = method.getName();
+ String sql = null;
+ Constructor<?> constructor = null;
+ if (compare(CREATE_STATEMENT,name)) {
+ //createStatement
+ constructor = getConstructor(CREATE_STATEMENT_IDX,Statement.class);
+ }else if (compare(PREPARE_STATEMENT,name)) {
+ //prepareStatement
+ sql = (String)args[0];
+ constructor = getConstructor(PREPARE_STATEMENT_IDX,PreparedStatement.class);
+ if (sql!=null) {
+ prepareStatement(sql, time);
+ }
+ }else if (compare(PREPARE_CALL,name)) {
+ //prepareCall
+ sql = (String)args[0];
+ constructor = getConstructor(PREPARE_CALL_IDX,CallableStatement.class);
+ prepareCall(sql,time);
+ }else {
+ //do nothing, might be a future unsupported method
+ //so we better bail out and let the system continue
+ return statement;
+ }
+ result = constructor.newInstance(new Object[] { new StatementProxy(statement,sql) });
+ return result;
+ }catch (Exception x) {
+ log.warn("Unable to create statement proxy for slow query report.",x);
+ }
+ return statement;
+ }
+
+
+ /**
+ * Class to measure query execute time
+ * @author fhanik
+ *
+ */
+ protected class StatementProxy implements InvocationHandler {
+ protected boolean closed = false;
+ protected Object delegate;
+ protected final String query;
+ public StatementProxy(Object parent, String query) {
+ this.delegate = parent;
+ this.query = query;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ //get the name of the method for comparison
+ final String name = method.getName();
+ //was close invoked?
+ boolean close = compare(JdbcInterceptor.CLOSE_VAL,name);
+ //allow close to be called multiple times
+ if (close && closed) return null;
+ //are we calling isClosed?
+ if (compare(JdbcInterceptor.ISCLOSED_VAL,name)) return Boolean.valueOf(closed);
+ //if we are calling anything else, bail out
+ if (closed) throw new SQLException("Statement closed.");
+ boolean process = false;
+ //check to see if we are about to execute a query
+ process = isExecute( method, process);
+ //if we are executing, get the current time
+ long start = (process)?System.currentTimeMillis():0;
+ Object result = null;
+ try {
+ //execute the query
+ result = method.invoke(delegate,args);
+ }catch (Throwable t) {
+ reportFailedQuery(query,args,name,start,t);
+ if (t instanceof InvocationTargetException) {
+ InvocationTargetException it = (InvocationTargetException)t;
+ throw it.getCause()!=null?it.getCause():it;
+ } else {
+ throw t;
+ }
+ }
+ //measure the time
+ long delta = (process)?(System.currentTimeMillis()-start):Long.MIN_VALUE;
+ //see if we meet the requirements to measure
+ if (delta>threshold) {
+ try {
+ //report the slow query
+ reportSlowQuery(query, args, name, start, delta);
+ }catch (Exception t) {
+ if (log.isWarnEnabled()) log.warn("Unable to process slow query",t);
+ }
+ } else if (process) {
+ reportQuery(query, args, name, start, delta);
+ }
+ //perform close cleanup
+ if (close) {
+ closed=true;
+ delegate = null;
+ }
+ return result;
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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 java.sql.SQLException;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+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.PoolConfiguration;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+/**
+ * Interceptor that keep track of connection state to avoid roundtrips to the database.
+ * The {@link org.apache.tomcat.jdbc.pool.ConnectionPool} is optimized to do as little work as possible.
+ * The pool itself doesn't remember settings like {@link java.sql.Connection#setAutoCommit(boolean)},
+ * {@link java.sql.Connection#setReadOnly(boolean)}, {@link java.sql.Connection#setCatalog(String)} or
+ * {@link java.sql.Connection#setTransactionIsolation(int)}. It relies on the application to remember how and when
+ * these settings have been applied.
+ * In the cases where the application code doesn't know or want to keep track of the state, this interceptor helps cache the
+ * state, and it also avoids roundtrips to the database asking for it.
+ * @author fhanik
+ *
+ */
+
+public class ConnectionState extends JdbcInterceptor {
+ private static final Log log = LogFactory.getLog(ConnectionState.class);
+
+ protected final String[] readState = {"getAutoCommit","getTransactionIsolation","isReadOnly","getCatalog"};
+ protected final String[] writeState = {"setAutoCommit","setTransactionIsolation","setReadOnly","setCatalog"};
+
+ protected Boolean autoCommit = null;
+ protected Integer transactionIsolation = null;
+ protected Boolean readOnly = null;
+ protected String catalog = null;
+
+
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ if (parent==null || con==null) {
+ //we are resetting, reset our defaults
+ autoCommit = null;
+ transactionIsolation = null;
+ readOnly = null;
+ catalog = null;
+ return;
+ }
+ PoolConfiguration poolProperties = parent.getPoolProperties();
+ if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) {
+ try {
+ if (transactionIsolation==null || transactionIsolation.intValue()!=poolProperties.getDefaultTransactionIsolation()) {
+ con.getConnection().setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
+ transactionIsolation = Integer.valueOf(poolProperties.getDefaultTransactionIsolation());
+ }
+ }catch (SQLException x) {
+ transactionIsolation = null;
+ log.error("Unable to reset transaction isolation state to connection.",x);
+ }
+ }
+ if (poolProperties.getDefaultReadOnly()!=null) {
+ try {
+ if (readOnly==null || readOnly.booleanValue()!=poolProperties.getDefaultReadOnly().booleanValue()) {
+ con.getConnection().setReadOnly(poolProperties.getDefaultReadOnly().booleanValue());
+ readOnly = poolProperties.getDefaultReadOnly();
+ }
+ }catch (SQLException x) {
+ readOnly = null;
+ log.error("Unable to reset readonly state to connection.",x);
+ }
+ }
+ if (poolProperties.getDefaultAutoCommit()!=null) {
+ try {
+ if (autoCommit==null || autoCommit.booleanValue()!=poolProperties.getDefaultAutoCommit().booleanValue()) {
+ con.getConnection().setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue());
+ autoCommit = poolProperties.getDefaultAutoCommit();
+ }
+ }catch (SQLException x) {
+ autoCommit = null;
+ log.error("Unable to reset autocommit state to connection.",x);
+ }
+ }
+ if (poolProperties.getDefaultCatalog()!=null) {
+ try {
+ if (catalog==null || (!catalog.equals(poolProperties.getDefaultCatalog()))) {
+ con.getConnection().setCatalog(poolProperties.getDefaultCatalog());
+ catalog = poolProperties.getDefaultCatalog();
+ }
+ }catch (SQLException x) {
+ catalog = null;
+ log.error("Unable to reset default catalog state to connection.",x);
+ }
+ }
+
+ }
+
+ @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 = compare(name,readState[i]);
+ if (read) index = i;
+ }
+ boolean write = false;
+ for (int i=0; (!write) && (!read) && i<writeState.length; i++) {
+ write = compare(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;}
+ case 3:{result = catalog; 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;}
+ case 3:{catalog = (String)(read?result:args[0]); break;}
+ }
+ }
+ return result;
+ }
+
+}
--- /dev/null
+/*
+ * 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.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+import org.apache.tomcat.jdbc.pool.ProxyConnection;
+
+/**
+ * Class that resets the abandoned timer on any activity on the
+ * Connection or any successful query executions.
+ * This interceptor is useful for when you have a {@link org.apache.tomcat.jdbc.pool.PoolConfiguration#setRemoveAbandonedTimeout(int)}
+ * that is fairly low, and you want to reset the abandoned time each time any operation on the connection is performed
+ * This is useful for batch processing programs that use connections for extensive amount of times.
+ * @author fhanik
+ *
+ */
+public class ResetAbandonedTimer extends AbstractQueryReport {
+
+ public ResetAbandonedTimer() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public boolean resetTimer() {
+ boolean result = false;
+ JdbcInterceptor interceptor = this.getNext();
+ while (interceptor!=null && result==false) {
+ if (interceptor instanceof ProxyConnection) {
+ PooledConnection con = ((ProxyConnection)interceptor).getConnection();
+ if (con!=null) {
+ con.setTimestamp(System.currentTimeMillis());
+ result = true;
+ } else {
+ break;
+ }
+ }
+ interceptor = interceptor.getNext();
+ }
+ return result;
+ }
+
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // TODO Auto-generated method stub
+ Object result = super.invoke(proxy, method, args);
+ resetTimer();
+ return result;
+ }
+
+ @Override
+ protected void prepareCall(String query, long time) {
+ resetTimer();
+ }
+
+ @Override
+ protected void prepareStatement(String sql, long time) {
+ resetTimer();
+
+ }
+
+ @Override
+ public void closeInvoked() {
+ resetTimer();
+ }
+
+ @Override
+ protected String reportQuery(String query, Object[] args, String name,long start, long delta) {
+ resetTimer();
+ return super.reportQuery(query, args, name, start, delta);
+ }
+
+ @Override
+ protected String reportSlowQuery(String query, Object[] args, String name,long start, long delta) {
+ resetTimer();
+ return super.reportSlowQuery(query, args, name, start, delta);
+ }
+}
--- /dev/null
+/*
+ * 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.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+
+/**
+ * Slow query report interceptor. Tracks timing of query executions.
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class SlowQueryReport extends AbstractQueryReport {
+ //logger
+ private static final Log log = LogFactory.getLog(SlowQueryReport.class);
+
+ /**
+ * we will be keeping track of query stats on a per pool basis
+ */
+ protected static ConcurrentHashMap<String,ConcurrentHashMap<String,QueryStats>> perPoolStats =
+ new ConcurrentHashMap<String,ConcurrentHashMap<String,QueryStats>>();
+ /**
+ * the queries that are used for this interceptor.
+ */
+ protected ConcurrentHashMap<String,QueryStats> queries = null;
+ /**
+ * Maximum number of queries we will be storing
+ */
+ protected int maxQueries= 1000; //don't store more than this amount of queries
+
+ /**
+ * Returns the query stats for a given pool
+ * @param poolname - the name of the pool we want to retrieve stats for
+ * @return a hash map containing statistics for 0 to maxQueries
+ */
+ public static ConcurrentHashMap<String,QueryStats> getPoolStats(String poolname) {
+ return perPoolStats.get(poolname);
+ }
+
+ /**
+ * Creates a slow query report interceptor
+ */
+ public SlowQueryReport() {
+ super();
+ }
+
+ public void setMaxQueries(int maxQueries) {
+ this.maxQueries = maxQueries;
+ }
+
+
+ @Override
+ protected String reportFailedQuery(String query, Object[] args, String name, long start, Throwable t) {
+ String sql = super.reportFailedQuery(query, args, name, start, t);
+ if (this.maxQueries > 0 ) {
+ long now = System.currentTimeMillis();
+ long delta = now - start;
+ QueryStats qs = this.getQueryStats(sql);
+ qs.failure(delta, now);
+ }
+ return sql;
+ }
+
+ @Override
+ protected String reportSlowQuery(String query, Object[] args, String name, long start, long delta) {
+ String sql = super.reportSlowQuery(query, args, name, start, delta);
+ if (this.maxQueries > 0 ) {
+ QueryStats qs = this.getQueryStats(sql);
+ qs.add(delta, start);
+ }
+ return sql;
+ }
+
+ /**
+ * invoked when the connection receives the close request
+ * Not used for now.
+ */
+ @Override
+ public void closeInvoked() {
+ queries = null;
+ }
+
+ @Override
+ public void prepareStatement(String sql, long time) {
+ QueryStats qs = getQueryStats(sql);
+ qs.prepare(time, System.currentTimeMillis());
+ }
+
+ @Override
+ public void prepareCall(String sql, long time) {
+ QueryStats qs = getQueryStats(sql);
+ qs.prepare(time, System.currentTimeMillis());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void poolStarted(ConnectionPool pool) {
+ super.poolStarted(pool);
+ //see if we already created a map for this pool
+ queries = SlowQueryReport.perPoolStats.get(pool.getName());
+ if (queries==null) {
+ //create the map to hold our stats
+ //however TODO we need to improve the eviction
+ //selection
+ queries = new ConcurrentHashMap<String,QueryStats>() {
+
+ };
+ if (perPoolStats.putIfAbsent(pool.getName(), queries)!=null) {
+ //there already was one
+ queries = SlowQueryReport.perPoolStats.get(pool.getName());
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void poolClosed(ConnectionPool pool) {
+ perPoolStats.remove(pool.getName());
+ super.poolClosed(pool);
+ }
+
+ protected QueryStats getQueryStats(String sql) {
+ ConcurrentHashMap<String,QueryStats> queries = SlowQueryReport.this.queries;
+ if (queries==null) return null;
+ QueryStats qs = queries.get(sql);
+ if (qs == null) {
+ qs = new QueryStats(sql);
+ if (queries.putIfAbsent(sql,qs)!=null) {
+ qs = queries.get(sql);
+ } else {
+ //we added a new element, see if we need to remove the oldest
+ if (queries.size() > maxQueries) {
+ removeOldest(queries);
+ }
+ }
+ }
+ return qs;
+ }
+
+ /**
+ * TODO - implement a better algorithm
+ * @param queries
+ */
+ protected void removeOldest(ConcurrentHashMap<String,QueryStats> queries) {
+ Iterator<String> it = queries.keySet().iterator();
+ while (queries.size()>maxQueries && it.hasNext()) {
+ String sql = it.next();
+ it.remove();
+ if (log.isDebugEnabled()) log.debug("Removing slow query, capacity reached:"+sql);
+ }
+ }
+
+
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ super.reset(parent, con);
+ if (parent!=null)
+ queries = SlowQueryReport.perPoolStats.get(parent.getName());
+ }
+
+
+ @Override
+ public void setProperties(Map<String, InterceptorProperty> properties) {
+ super.setProperties(properties);
+ final String threshold = "threshold";
+ final String maxqueries= "maxQueries";
+ InterceptorProperty p1 = properties.get(threshold);
+ InterceptorProperty p2 = properties.get(maxqueries);
+ if (p1!=null) {
+ setThreshold(Long.parseLong(p1.getValue()));
+ }
+ if (p2!=null) {
+ setMaxQueries(Integer.parseInt(p2.getValue()));
+ }
+ }
+
+
+ /**
+ *
+ * @author fhanik
+ *
+ */
+ public static class QueryStats {
+ static final String[] FIELD_NAMES = new String[] {
+ "query",
+ "nrOfInvocations",
+ "maxInvocationTime",
+ "maxInvocationDate",
+ "minInvocationTime",
+ "minInvocationDate",
+ "totalInvocationTime",
+ "failures",
+ "prepareCount",
+ "prepareTime",
+ "lastInvocation"
+ };
+
+ static final String[] FIELD_DESCRIPTIONS = new String[] {
+ "The SQL query",
+ "The number of query invocations, a call to executeXXX",
+ "The longest time for this query in milliseconds",
+ "The time and date for when the longest query took place",
+ "The shortest time for this query in milliseconds",
+ "The time and date for when the shortest query took place",
+ "The total amount of milliseconds spent executing this query",
+ "The number of failures for this query",
+ "The number of times this query was prepared (prepareStatement/prepareCall)",
+ "The total number of milliseconds spent preparing this query",
+ "The date and time of the last invocation"
+ };
+
+ static final OpenType[] FIELD_TYPES = new OpenType[] {
+ SimpleType.STRING,
+ SimpleType.INTEGER,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.INTEGER,
+ SimpleType.LONG,
+ SimpleType.LONG
+ };
+
+ private final String query;
+ private int nrOfInvocations;
+ private long maxInvocationTime = Long.MIN_VALUE;
+ private long maxInvocationDate;
+ private long minInvocationTime = Long.MAX_VALUE;
+ private long minInvocationDate;
+ private long totalInvocationTime;
+ private long failures;
+ private int prepareCount;
+ private long prepareTime;
+ private volatile long lastInvocation = 0;
+
+ public static String[] getFieldNames() {
+ return FIELD_NAMES;
+ }
+
+ public static String[] getFieldDescriptions() {
+ return FIELD_DESCRIPTIONS;
+ }
+
+ public static OpenType[] getFieldTypes() {
+ return FIELD_TYPES;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder("QueryStats[query:");
+ buf.append(query);
+ buf.append(", nrOfInvocations:");
+ buf.append(nrOfInvocations);
+ buf.append(", maxInvocationTime:");
+ buf.append(maxInvocationTime);
+ buf.append(", maxInvocationDate:");
+ buf.append(new java.util.Date(maxInvocationDate).toGMTString());
+ buf.append(", minInvocationTime:");
+ buf.append(minInvocationTime);
+ buf.append(", minInvocationDate:");
+ buf.append(new java.util.Date(minInvocationDate).toGMTString());
+ buf.append(", totalInvocationTime:");
+ buf.append(totalInvocationTime);
+ buf.append(", averageInvocationTime:");
+ buf.append((float)totalInvocationTime / (float)nrOfInvocations);
+ buf.append(", failures:");
+ buf.append(failures);
+ buf.append(", prepareCount:");
+ buf.append(prepareCount);
+ buf.append(", prepareTime:");
+ buf.append(prepareTime);
+ buf.append("]");
+ return buf.toString();
+ }
+
+ public CompositeDataSupport getCompositeData(final CompositeType type) throws OpenDataException{
+ Object[] values = new Object[] {
+ query,
+ Integer.valueOf(nrOfInvocations),
+ Long.valueOf(maxInvocationTime),
+ Long.valueOf(maxInvocationDate),
+ Long.valueOf(minInvocationTime),
+ Long.valueOf(minInvocationDate),
+ Long.valueOf(totalInvocationTime),
+ Long.valueOf(failures),
+ Integer.valueOf(prepareCount),
+ Long.valueOf(prepareTime),
+ Long.valueOf(lastInvocation)
+ };
+ return new CompositeDataSupport(type,FIELD_NAMES,values);
+ }
+
+ public QueryStats(String query) {
+ this.query = query;
+ }
+
+ public void prepare(long invocationTime, long now) {
+ prepareCount++;
+ prepareTime+=invocationTime;
+
+ }
+
+ public void add(long invocationTime, long now) {
+ //not thread safe, but don't sacrifice performance for this kind of stuff
+ maxInvocationTime = Math.max(invocationTime, maxInvocationTime);
+ if (maxInvocationTime == invocationTime) {
+ maxInvocationDate = now;
+ }
+ minInvocationTime = Math.min(invocationTime, minInvocationTime);
+ if (minInvocationTime==invocationTime) {
+ minInvocationDate = now;
+ }
+ nrOfInvocations++;
+ totalInvocationTime+=invocationTime;
+ lastInvocation = now;
+ }
+
+ public void failure(long invocationTime, long now) {
+ add(invocationTime,now);
+ failures++;
+
+ }
+
+ public String getQuery() {
+ return query;
+ }
+
+ public int getNrOfInvocations() {
+ return nrOfInvocations;
+ }
+
+ public long getMaxInvocationTime() {
+ return maxInvocationTime;
+ }
+
+ public long getMaxInvocationDate() {
+ return maxInvocationDate;
+ }
+
+ public long getMinInvocationTime() {
+ return minInvocationTime;
+ }
+
+ public long getMinInvocationDate() {
+ return minInvocationDate;
+ }
+
+ public long getTotalInvocationTime() {
+ return totalInvocationTime;
+ }
+
+ @Override
+ public int hashCode() {
+ return query.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof QueryStats) {
+ QueryStats qs = (QueryStats)other;
+ return qs.query.equals(this.query);
+ }
+ return false;
+ }
+
+ public boolean isOlderThan(QueryStats other) {
+ return this.lastInvocation < other.lastInvocation;
+ }
+ }
+
+
+}
--- /dev/null
+/*
+ * 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.management.ManagementFactory;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+/**
+ * Publishes data to JMX and provides notifications
+ * when failures happen.
+ * @author fhanik
+ *
+ */
+public class SlowQueryReportJmx extends SlowQueryReport implements NotificationEmitter, SlowQueryReportJmxMBean{
+ public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY";
+ public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY";
+
+ protected static CompositeType SLOW_QUERY_TYPE;
+
+ private static final Log log = LogFactory.getLog(SlowQueryReportJmx.class);
+
+
+ protected static ConcurrentHashMap<String,SlowQueryReportJmxMBean> mbeans =
+ new ConcurrentHashMap<String,SlowQueryReportJmxMBean>();
+
+
+ //==============================JMX STUFF========================
+ protected volatile NotificationBroadcasterSupport notifier = new NotificationBroadcasterSupport();
+
+ public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException {
+ notifier.addNotificationListener(listener, filter, handback);
+ }
+
+
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ return notifier.getNotificationInfo();
+ }
+
+ public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
+ notifier.removeNotificationListener(listener);
+
+ }
+
+ public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
+ notifier.removeNotificationListener(listener, filter, handback);
+
+ }
+
+
+ //==============================JMX STUFF========================
+
+ protected String poolName = null;
+
+ protected static AtomicLong notifySequence = new AtomicLong(0);
+
+ protected boolean notifyPool = true;
+
+ protected ConnectionPool pool = null;
+
+ protected static CompositeType getCompositeType() {
+ if (SLOW_QUERY_TYPE==null) {
+ try {
+ SLOW_QUERY_TYPE = new CompositeType(
+ SlowQueryReportJmx.class.getName(),
+ "Composite data type for query statistics",
+ QueryStats.getFieldNames(),
+ QueryStats.getFieldDescriptions(),
+ QueryStats.getFieldTypes());
+ }catch (OpenDataException x) {
+ log.warn("Unable to initialize composite data type for JMX stats and notifications.",x);
+ }
+ }
+ return SLOW_QUERY_TYPE;
+ }
+
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ // TODO Auto-generated method stub
+ super.reset(parent, con);
+ if (parent!=null) {
+ poolName = parent.getName();
+ pool = parent;
+ registerJmx();
+ }
+ }
+
+
+ @Override
+ public void poolClosed(ConnectionPool pool) {
+ this.poolName = pool.getName();
+ deregisterJmx();
+ super.poolClosed(pool);
+ }
+
+ @Override
+ public void poolStarted(ConnectionPool pool) {
+ this.pool = pool;
+ super.poolStarted(pool);
+ this.poolName = pool.getName();
+ }
+
+ @Override
+ protected String reportFailedQuery(String query, Object[] args, String name, long start, Throwable t) {
+ query = super.reportFailedQuery(query, args, name, start, t);
+ notifyJmx(query,FAILED_QUERY_NOTIFICATION);
+ return query;
+ }
+
+ protected void notifyJmx(String query, String type) {
+ try {
+ long sequence = notifySequence.incrementAndGet();
+
+ if (isNotifyPool()) {
+ if (this.pool!=null && this.pool.getJmxPool()!=null) {
+ this.pool.getJmxPool().notify(type, query);
+ }
+ } else {
+ if (notifier!=null) {
+ Notification notification =
+ new Notification(type,
+ this,
+ sequence,
+ System.currentTimeMillis(),
+ query);
+
+ notifier.sendNotification(notification);
+ }
+ }
+ } catch (RuntimeOperationsException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to send failed query notification.",e);
+ }
+ }
+ }
+
+ @Override
+ protected String reportSlowQuery(String query, Object[] args, String name, long start, long delta) {
+ query = super.reportSlowQuery(query, args, name, start, delta);
+ notifyJmx(query,SLOW_QUERY_NOTIFICATION);
+ return query;
+ }
+
+ /**
+ * JMX operation - return the names of all the pools
+ * @return - all the names of pools that we have stored data for
+ */
+ public String[] getPoolNames() {
+ Set<String> keys = perPoolStats.keySet();
+ return keys.toArray(new String[0]);
+ }
+
+ /**
+ * JMX operation - return the name of the pool
+ * @return the name of the pool, unique within the JVM
+ */
+ public String getPoolName() {
+ return poolName;
+ }
+
+
+ public boolean isNotifyPool() {
+ return notifyPool;
+ }
+
+ public void setNotifyPool(boolean notifyPool) {
+ this.notifyPool = notifyPool;
+ }
+
+ /**
+ * JMX operation - remove all stats for this connection pool
+ */
+ public void resetStats() {
+ ConcurrentHashMap<String,QueryStats> queries = perPoolStats.get(poolName);
+ if (queries!=null) {
+ Iterator<String> it = queries.keySet().iterator();
+ while (it.hasNext()) it.remove();
+ }
+ }
+
+ /**
+ * JMX operation - returns all the queries we have collected.
+ * @return - the slow query report as composite data.
+ */
+ public CompositeData[] getSlowQueriesCD() throws OpenDataException {
+ CompositeDataSupport[] result = null;
+ ConcurrentHashMap<String,QueryStats> queries = perPoolStats.get(poolName);
+ if (queries!=null) {
+ Set<Map.Entry<String,QueryStats>> stats = queries.entrySet();
+ if (stats!=null) {
+ result = new CompositeDataSupport[stats.size()];
+ Iterator<Map.Entry<String,QueryStats>> it = stats.iterator();
+ int pos = 0;
+ while (it.hasNext()) {
+ Map.Entry<String,QueryStats> entry = it.next();
+ QueryStats qs = entry.getValue();
+ result[pos++] = qs.getCompositeData(getCompositeType());
+ }
+ }
+ }
+ return result;
+ }
+
+ protected void deregisterJmx() {
+ try {
+ if (mbeans.remove(poolName)!=null) {
+ ObjectName oname = getObjectName(getClass(),poolName);
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(oname);
+ }
+ } catch (MBeanRegistrationException e) {
+ log.debug("Jmx deregistration failed.",e);
+ } catch (InstanceNotFoundException e) {
+ log.debug("Jmx deregistration failed.",e);
+ } catch (MalformedObjectNameException e) {
+ log.warn("Jmx deregistration failed.",e);
+ } catch (RuntimeOperationsException e) {
+ log.warn("Jmx deregistration failed.",e);
+ }
+
+ }
+
+
+ public static ObjectName getObjectName(Class<?> clazz, String poolName) throws MalformedObjectNameException {
+ ObjectName oname = new ObjectName(ConnectionPool.POOL_JMX_TYPE_PREFIX+clazz.getName()+",name=" + poolName);
+ return oname;
+ }
+
+ protected void registerJmx() {
+ try {
+ //only if we notify the pool itself
+ if (isNotifyPool()) {
+
+ } else if (getCompositeType()!=null) {
+ ObjectName oname = getObjectName(getClass(),poolName);
+ if (mbeans.putIfAbsent(poolName, this)==null) {
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this, oname);
+ }
+ } else {
+ log.warn(SlowQueryReport.class.getName()+ "- No JMX support, composite type was not found.");
+ }
+ } catch (MalformedObjectNameException e) {
+ log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+ } catch (RuntimeOperationsException e) {
+ log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+ } catch (MBeanException e) {
+ log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+ } catch (InstanceAlreadyExistsException e) {
+ log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+ } catch (NotCompliantMBeanException e) {
+ log.error("Jmx registration failed, no JMX data will be exposed for the query stats.",e);
+ }
+ }
+
+ @Override
+ public void setProperties(Map<String, InterceptorProperty> properties) {
+ super.setProperties(properties);
+ final String threshold = "notifyPool";
+ InterceptorProperty p1 = properties.get(threshold);
+ if (p1!=null) {
+ this.setNotifyPool(Boolean.parseBoolean(p1.getValue()));
+ }
+ }
+
+
+}
--- /dev/null
+/* 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 javax.management.openmbean.CompositeData;
+import javax.management.openmbean.OpenDataException;
+
+public interface SlowQueryReportJmxMBean {
+ public CompositeData[] getSlowQueriesCD() throws OpenDataException;
+}
--- /dev/null
+/* 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.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Statement;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+
+public class StatementCache extends StatementDecoratorInterceptor {
+ protected static final String[] ALL_TYPES = new String[] {PREPARE_STATEMENT,PREPARE_CALL};
+ protected static final String[] CALLABLE_TYPE = new String[] {PREPARE_CALL};
+ protected static final String[] PREPARED_TYPE = new String[] {PREPARE_STATEMENT};
+ protected static final String[] NO_TYPE = new String[] {};
+
+ protected static final String STATEMENT_CACHE_ATTR = StatementCache.class.getName() + ".cache";
+
+ /*begin properties for the statement cache*/
+ private boolean cachePrepared = true;
+ private boolean cacheCallable = false;
+ private int maxCacheSize = 50;
+ private PooledConnection pcon;
+ private String[] types;
+
+
+ public boolean isCachePrepared() {
+ return cachePrepared;
+ }
+
+ public boolean isCacheCallable() {
+ return cacheCallable;
+ }
+
+ public int getMaxCacheSize() {
+ return maxCacheSize;
+ }
+
+ public String[] getTypes() {
+ return types;
+ }
+
+ public AtomicInteger getCacheSize() {
+ return cacheSize;
+ }
+
+ @Override
+ public void setProperties(Map<String, InterceptorProperty> properties) {
+ super.setProperties(properties);
+ InterceptorProperty p = properties.get("prepared");
+ if (p!=null) cachePrepared = p.getValueAsBoolean(cachePrepared);
+ p = properties.get("callable");
+ if (p!=null) cacheCallable = p.getValueAsBoolean(cacheCallable);
+ p = properties.get("max");
+ if (p!=null) maxCacheSize = p.getValueAsInt(maxCacheSize);
+ if (cachePrepared && cacheCallable) {
+ this.types = ALL_TYPES;
+ } else if (cachePrepared) {
+ this.types = PREPARED_TYPE;
+ } else if (cacheCallable) {
+ this.types = CALLABLE_TYPE;
+ } else {
+ this.types = NO_TYPE;
+ }
+
+ }
+ /*end properties for the statement cache*/
+
+ /*begin the cache size*/
+ private static ConcurrentHashMap<ConnectionPool,AtomicInteger> cacheSizeMap =
+ new ConcurrentHashMap<ConnectionPool,AtomicInteger>();
+
+ private AtomicInteger cacheSize;
+
+ @Override
+ public void poolStarted(ConnectionPool pool) {
+ cacheSizeMap.putIfAbsent(pool, new AtomicInteger(0));
+ super.poolStarted(pool);
+ }
+
+ @Override
+ public void poolClosed(ConnectionPool pool) {
+ cacheSizeMap.remove(pool);
+ super.poolClosed(pool);
+ }
+ /*end the cache size*/
+
+ /*begin the actual statement cache*/
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ super.reset(parent, con);
+ if (parent==null) {
+ cacheSize = null;
+ this.pcon = null;
+ } else {
+ cacheSize = cacheSizeMap.get(parent);
+ this.pcon = con;
+ if (!pcon.getAttributes().containsKey(STATEMENT_CACHE_ATTR)) {
+ ConcurrentHashMap<String,CachedStatement> cache = new ConcurrentHashMap<String, CachedStatement>();
+ pcon.getAttributes().put(STATEMENT_CACHE_ATTR,cache);
+ }
+ }
+ }
+
+ @Override
+ public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) {
+ ConcurrentHashMap<String,CachedStatement> statements =
+ (ConcurrentHashMap<String,CachedStatement>)con.getAttributes().get(STATEMENT_CACHE_ATTR);
+
+ if (statements!=null) {
+ for (Map.Entry<String, CachedStatement> p : statements.entrySet()) {
+ closeStatement(p.getValue());
+ }
+ statements.clear();
+ }
+
+ super.disconnected(parent, con, finalizing);
+ }
+
+ public void closeStatement(CachedStatement st) {
+ if (st==null) return;
+ st.forceClose();
+ }
+
+ @Override
+ protected Object createDecorator(Object proxy, Method method, Object[] args,
+ Object statement, Constructor<?> constructor, String sql)
+ throws InstantiationException, IllegalAccessException, InvocationTargetException {
+ boolean process = process(this.types, method, false);
+ if (process) {
+ Object result = null;
+ CachedStatement statementProxy = new CachedStatement((Statement)statement,sql);
+ result = constructor.newInstance(new Object[] { statementProxy });
+ statementProxy.setActualProxy(result);
+ statementProxy.setConnection(proxy);
+ statementProxy.setConstructor(constructor);
+ return result;
+ } else {
+ return super.createDecorator(proxy, method, args, statement, constructor, sql);
+ }
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ boolean process = process(this.types, method, false);
+ if (process && args.length>0 && args[0] instanceof String) {
+ CachedStatement statement = isCached((String)args[0]);
+ if (statement!=null) {
+ //remove it from the cache since it is used
+ removeStatement(statement);
+ return statement.getActualProxy();
+ } else {
+ return super.invoke(proxy, method, args);
+ }
+ } else {
+ return super.invoke(proxy,method,args);
+ }
+ }
+
+ public CachedStatement isCached(String sql) {
+ ConcurrentHashMap<String,CachedStatement> cache =
+ (ConcurrentHashMap<String,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
+ return cache.get(sql);
+ }
+
+ public boolean cacheStatement(CachedStatement proxy) {
+ ConcurrentHashMap<String,CachedStatement> cache =
+ (ConcurrentHashMap<String,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
+ if (proxy.getSql()==null) {
+ return false;
+ } else if (cache.containsKey(proxy.getSql())) {
+ return false;
+ } else if (cacheSize.get()>=maxCacheSize) {
+ return false;
+ } else if (cacheSize.incrementAndGet()>maxCacheSize) {
+ cacheSize.decrementAndGet();
+ return false;
+ } else {
+ //cache the statement
+ cache.put(proxy.getSql(), proxy);
+ return true;
+ }
+ }
+
+ public boolean removeStatement(CachedStatement proxy) {
+ ConcurrentHashMap<String,CachedStatement> cache =
+ (ConcurrentHashMap<String,CachedStatement>)pcon.getAttributes().get(STATEMENT_CACHE_ATTR);
+ if (cache.remove(proxy.getSql()) != null) {
+ cacheSize.decrementAndGet();
+ return true;
+ } else {
+ return false;
+ }
+ }
+ /*end the actual statement cache*/
+
+
+ protected class CachedStatement extends StatementDecoratorInterceptor.StatementProxy<Statement> {
+ boolean cached = false;
+ public CachedStatement(Statement parent, String sql) {
+ super(parent, sql);
+ }
+
+ @Override
+ public void closeInvoked() {
+ //should we cache it
+ boolean shouldClose = true;
+ if (cacheSize.get() < maxCacheSize) {
+ //cache a proxy so that we don't reuse the facade
+ CachedStatement proxy = new CachedStatement(getDelegate(),getSql());
+ try {
+ //create a new facade
+ Object actualProxy = getConstructor().newInstance(new Object[] { proxy });
+ proxy.setActualProxy(actualProxy);
+ proxy.setConnection(getConnection());
+ proxy.setConstructor(getConstructor());
+ if (cacheStatement(proxy)) {
+ proxy.cached = true;
+ shouldClose = false;
+ }
+ } catch (Exception x) {
+ removeStatement(proxy);
+ }
+ }
+ closed = true;
+ delegate = null;
+ if (shouldClose) {
+ super.closeInvoked();
+ }
+
+ }
+
+ public void forceClose() {
+ removeStatement(this);
+ super.closeInvoked();
+ }
+
+ }
+
+}
+
+
--- /dev/null
+/*
+ * 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.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor;
+
+/**
+ * Implementation of <b>JdbcInterceptor</b> that proxies resultSets and statements.
+ * @author Guillermo Fernandes
+ */
+public class StatementDecoratorInterceptor extends AbstractCreateStatementInterceptor {
+
+ private static final Log logger = LogFactory.getLog(StatementDecoratorInterceptor.class);
+
+ private static final String[] EXECUTE_QUERY_TYPES = { "executeQuery" };
+
+ /**
+ * the constructors that are used to create statement proxies
+ */
+ protected static final Constructor<?>[] constructors = new Constructor[AbstractCreateStatementInterceptor.STATEMENT_TYPE_COUNT];
+
+ /**
+ * the constructor to create the resultSet proxies
+ */
+ protected static Constructor<?> resultSetConstructor = null;
+
+ @Override
+ public void closeInvoked() {
+ // nothing to do
+ }
+
+ /**
+ * Creates a constructor for a proxy class, if one doesn't already exist
+ *
+ * @param idx
+ * - the index of the constructor
+ * @param clazz
+ * - the interface that the proxy will implement
+ * @return - returns a constructor used to create new instances
+ * @throws NoSuchMethodException
+ */
+ protected Constructor<?> getConstructor(int idx, Class<?> clazz) throws NoSuchMethodException {
+ if (constructors[idx] == null) {
+ Class<?> proxyClass = Proxy.getProxyClass(StatementDecoratorInterceptor.class.getClassLoader(),
+ new Class[] { clazz });
+ constructors[idx] = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+ }
+ return constructors[idx];
+ }
+
+ protected Constructor<?> getResultSetConstructor() throws NoSuchMethodException {
+ if (resultSetConstructor == null) {
+ Class<?> proxyClass = Proxy.getProxyClass(StatementDecoratorInterceptor.class.getClassLoader(),
+ new Class[] { ResultSet.class });
+ resultSetConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+ }
+ return resultSetConstructor;
+ }
+
+ /**
+ * Creates a statement interceptor to monitor query response times
+ */
+ @Override
+ public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
+ try {
+ String name = method.getName();
+ Constructor<?> constructor = null;
+ String sql = null;
+ if (compare(CREATE_STATEMENT, name)) {
+ // createStatement
+ constructor = getConstructor(CREATE_STATEMENT_IDX, Statement.class);
+ } else if (compare(PREPARE_STATEMENT, name)) {
+ // prepareStatement
+ constructor = getConstructor(PREPARE_STATEMENT_IDX, PreparedStatement.class);
+ sql = (String)args[0];
+ } else if (compare(PREPARE_CALL, name)) {
+ // prepareCall
+ constructor = getConstructor(PREPARE_CALL_IDX, CallableStatement.class);
+ sql = (String)args[0];
+ } else {
+ // do nothing, might be a future unsupported method
+ // so we better bail out and let the system continue
+ return statement;
+ }
+ return createDecorator(proxy, method, args, statement, constructor, sql);
+ } catch (Exception x) {
+ logger.warn("Unable to create statement proxy for slow query report.", x);
+ }
+ return statement;
+ }
+
+ protected Object createDecorator(Object proxy, Method method, Object[] args,
+ Object statement, Constructor<?> constructor, String sql)
+ throws InstantiationException, IllegalAccessException, InvocationTargetException {
+ Object result = null;
+ StatementProxy statementProxy = new StatementProxy<Statement>((Statement)statement,sql);
+ result = constructor.newInstance(new Object[] { statementProxy });
+ statementProxy.setActualProxy(result);
+ statementProxy.setConnection(proxy);
+ statementProxy.setConnection(constructor);
+ return result;
+ }
+
+ protected boolean isExecuteQuery(String methodName) {
+ return EXECUTE_QUERY_TYPES[0].equals(methodName);
+ }
+
+ protected boolean isExecuteQuery(Method method) {
+ return isExecuteQuery(method.getName());
+ }
+
+ /**
+ * Class to measure query execute time
+ *
+ * @author fhanik
+ *
+ */
+ protected class StatementProxy<T extends java.sql.Statement> implements InvocationHandler {
+
+ protected boolean closed = false;
+ protected T delegate;
+ private Object actualProxy;
+ private Object connection;
+ private String sql;
+ private Constructor constructor;
+
+ public StatementProxy(T delegate, String sql) {
+ this.delegate = delegate;
+ this.sql = sql;
+ }
+ public T getDelegate() {
+ return this.delegate;
+ }
+
+ public String getSql() {
+ return sql;
+ }
+
+ public void setConnection(Object proxy) {
+ this.connection = proxy;
+ }
+ public Object getConnection() {
+ return this.connection;
+ }
+
+ public void setActualProxy(Object proxy){
+ this.actualProxy = proxy;
+ }
+ public Object getActualProxy() {
+ return this.actualProxy;
+ }
+
+
+ public Constructor getConstructor() {
+ return constructor;
+ }
+ public void setConstructor(Constructor constructor) {
+ this.constructor = constructor;
+ }
+ public void closeInvoked() {
+ if (getDelegate()!=null) {
+ try {
+ getDelegate().close();
+ }catch (SQLException ignore) {
+ }
+ }
+ closed = true;
+ delegate = null;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (compare(TOSTRING_VAL,method)) {
+ return toString();
+ }
+ // was close invoked?
+ boolean close = compare(CLOSE_VAL, method);
+ // allow close to be called multiple times
+ if (close && closed)
+ return null;
+ // are we calling isClosed?
+ if (compare(ISCLOSED_VAL, method))
+ return Boolean.valueOf(closed);
+ // if we are calling anything else, bail out
+ if (closed)
+ throw new SQLException("Statement closed.");
+ if (compare(GETCONNECTION_VAL,method)){
+ return connection;
+ }
+ boolean process = isExecuteQuery(method);
+ // check to see if we are about to execute a query
+ // if we are executing, get the current time
+ Object result = null;
+ try {
+ // perform close cleanup
+ if (close) {
+ closeInvoked();
+ } else {
+ // execute the query
+ result = method.invoke(delegate, args);
+ }
+ } catch (Throwable t) {
+ if (t instanceof InvocationTargetException) {
+ InvocationTargetException it = (InvocationTargetException) t;
+ throw it.getCause() != null ? it.getCause() : it;
+ } else {
+ throw t;
+ }
+ }
+ if (process){
+ Constructor<?> cons = getResultSetConstructor();
+ result = cons.newInstance(new Object[]{new ResultSetProxy(actualProxy, result)});
+ }
+ return result;
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer(StatementProxy.class.getName());
+ buf.append("[Proxy=");
+ buf.append(System.identityHashCode(this));
+ buf.append("; Sql=");
+ buf.append(getSql());
+ buf.append("; Delegate=");
+ buf.append(getDelegate());
+ buf.append("; Connection=");
+ buf.append(getConnection());
+ buf.append("]");
+ return buf.toString();
+ }
+ }
+
+ protected class ResultSetProxy implements InvocationHandler {
+
+ private Object st;
+ private Object delegate;
+
+ public ResultSetProxy(Object st, Object delegate) {
+ this.st = st;
+ this.delegate = delegate;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("getStatement")) {
+ return this.st;
+ } else {
+ return method.invoke(this.delegate, args);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.sql.Statement;
+import java.util.ArrayList;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+/**
+ * Keeps track of statements associated with a connection and invokes close upon {@link java.sql.Connection#close()}
+ * Useful for applications that dont close the associated statements after being done with a connection.
+ * @author fhanik
+ *
+ */
+public class StatementFinalizer extends AbstractCreateStatementInterceptor {
+ private static final Log log = LogFactory.getLog(StatementFinalizer.class);
+
+ protected ArrayList<WeakReference<Statement>> statements = new ArrayList<WeakReference<Statement>>();
+
+ @Override
+ public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) {
+ // TODO Auto-generated method stub
+ try {
+ if (statement instanceof Statement)
+ statements.add(new WeakReference<Statement>((Statement)statement));
+ }catch (ClassCastException x) {
+ //ignore this one
+ }
+ return statement;
+ }
+
+ @Override
+ public void closeInvoked() {
+ while (statements.size()>0) {
+ WeakReference<Statement> ws = statements.remove(0);
+ Statement st = ws.get();
+ if (st!=null) {
+ try {
+ st.close();
+ } catch (Exception ignore) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to closed statement upon connection close.",ignore);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ statements.clear();
+ super.reset(parent, con);
+ }
+
+
+}
--- /dev/null
+<?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.
+-->
+<mbeans-descriptors>
+
+ <mbean description="Reports " domain="tomcat.jdbc" group="jdbc-pool" name="SlowQueryReportJmx"
+ type="org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx">
+
+ <attribute description="The name of the connection pool this Jmx bean is representing" name="poolName" type="java.lang.String" writeable="false"/>
+ <attribute description="List of all registered connections pools" name="poolNames" type="[java.lang.String;" writeable="false"/>
+ <attribute description="All the recorded query stats. " name="slowQueriesCD" type="[javax.management.openmbean.CompositeData;" writeable="false"/>
+ <operation description="Clears all the query stats" impact="ACTION" name="resetStats" returnType="void"/>
+
+ <notification description="Notification sent out by the slow query report when a query exceeds the threshhold" name="slow-query">
+ <notification-type>Slow query</notification-type>
+ </notification>
+
+ <notification description="Notification sent out by the slow query report when a query fails execution" name="failed-query">
+ <notification-type>Failed query execution</notification-type>
+ </notification>
+ </mbean>
+</mbeans-descriptors>
\ No newline at end of file
--- /dev/null
+/* 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 java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationListener;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.apache.tomcat.jdbc.pool.PoolUtilities;
+import org.apache.tomcat.jdbc.pool.Validator;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
+
+public class ConnectionPool extends NotificationBroadcasterSupport implements ConnectionPoolMBean {
+ /**
+ * logger
+ */
+ private static final Log log = LogFactory.getLog(ConnectionPool.class);
+
+ /**
+ * the connection pool
+ */
+ protected org.apache.tomcat.jdbc.pool.ConnectionPool pool = null;
+ /**
+ * sequence for JMX notifications
+ */
+ protected AtomicInteger sequence = new AtomicInteger(0);
+
+ /**
+ * Listeners that are local and interested in our notifications, no need for JMX
+ */
+ protected ConcurrentLinkedQueue<NotificationListener> listeners = new ConcurrentLinkedQueue<NotificationListener>();
+
+ public ConnectionPool(org.apache.tomcat.jdbc.pool.ConnectionPool pool) {
+ super();
+ this.pool = pool;
+ }
+
+ public org.apache.tomcat.jdbc.pool.ConnectionPool getPool() {
+ return pool;
+ }
+
+ public PoolConfiguration getPoolProperties() {
+ return pool.getPoolProperties();
+ }
+
+ //=================================================================
+ // NOTIFICATION INFO
+ //=================================================================
+ public static final String NOTIFY_INIT = "INIT FAILED";
+ public static final String NOTIFY_CONNECT = "CONNECTION FAILED";
+ public static final String NOTIFY_ABANDON = "CONNECTION ABANDONED";
+ public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY";
+ public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY";
+ public static final String SUSPECT_ABANDONED_NOTIFICATION = "SUSPECT CONNETION ABANDONED";
+
+ @Override
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ MBeanNotificationInfo[] pres = super.getNotificationInfo();
+ MBeanNotificationInfo[] loc = getDefaultNotificationInfo();
+ MBeanNotificationInfo[] aug = new MBeanNotificationInfo[pres.length + loc.length];
+ if (pres.length>0) System.arraycopy(pres, 0, aug, 0, pres.length);
+ if (loc.length >0) System.arraycopy(loc, 0, aug, pres.length, loc.length);
+ return aug;
+ }
+
+ public static MBeanNotificationInfo[] getDefaultNotificationInfo() {
+ String[] types = new String[] {NOTIFY_INIT, NOTIFY_CONNECT, NOTIFY_ABANDON, SLOW_QUERY_NOTIFICATION, FAILED_QUERY_NOTIFICATION, SUSPECT_ABANDONED_NOTIFICATION};
+ String name = Notification.class.getName();
+ String description = "A connection pool error condition was met.";
+ MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
+ return new MBeanNotificationInfo[] {info};
+ }
+
+ /**
+ * Return true if the notification was sent successfully, false otherwise.
+ * @param type
+ * @param message
+ * @return true if the notification succeeded
+ */
+ public boolean notify(final String type, String message) {
+ try {
+ Notification n = new Notification(
+ type,
+ this,
+ sequence.incrementAndGet(),
+ System.currentTimeMillis(),
+ "["+type+"] "+message);
+ sendNotification(n);
+ for (NotificationListener listener : listeners) {
+ listener.handleNotification(n,this);
+ }
+ return true;
+ }catch (Exception x) {
+ if (log.isDebugEnabled()) {
+ log.debug("Notify failed. Type="+type+"; Message="+message,x);
+ }
+ return false;
+ }
+
+ }
+
+ public void addListener(NotificationListener list) {
+ listeners.add(list);
+ }
+
+ public boolean removeListener(NotificationListener list) {
+ return listeners.remove(list);
+ }
+
+ //=================================================================
+ // POOL STATS
+ //=================================================================
+
+ public int getSize() {
+ return pool.getSize();
+ }
+
+ public int getIdle() {
+ return pool.getIdle();
+ }
+
+ public int getActive() {
+ return pool.getActive();
+ }
+
+ public int getNumIdle() {
+ return getIdle();
+ }
+
+ public int getNumActive() {
+ return getActive();
+ }
+
+ public int getWaitCount() {
+ return pool.getWaitCount();
+ }
+
+ //=================================================================
+ // POOL OPERATIONS
+ //=================================================================
+ public void checkIdle() {
+ pool.checkIdle();
+ }
+
+ public void checkAbandoned() {
+ pool.checkAbandoned();
+ }
+
+ public void testIdle() {
+ pool.testAllIdle();
+ }
+ //=================================================================
+ // POOL PROPERTIES
+ //=================================================================
+ //=========================================================
+ // PROPERTIES / CONFIGURATION
+ //=========================================================
+
+
+ public String getConnectionProperties() {
+ return getPoolProperties().getConnectionProperties();
+ }
+
+ public Properties getDbProperties() {
+ return PoolUtilities.cloneWithoutPassword(getPoolProperties().getDbProperties());
+ }
+
+ public String getDefaultCatalog() {
+ return getPoolProperties().getDefaultCatalog();
+ }
+
+ public int getDefaultTransactionIsolation() {
+ return getPoolProperties().getDefaultTransactionIsolation();
+ }
+
+ public String getDriverClassName() {
+ return getPoolProperties().getDriverClassName();
+ }
+
+
+ public int getInitialSize() {
+ return getPoolProperties().getInitialSize();
+ }
+
+ public String getInitSQL() {
+ return getPoolProperties().getInitSQL();
+ }
+
+ public String getJdbcInterceptors() {
+ return getPoolProperties().getJdbcInterceptors();
+ }
+
+ public int getMaxActive() {
+ return getPoolProperties().getMaxActive();
+ }
+
+ public int getMaxIdle() {
+ return getPoolProperties().getMaxIdle();
+ }
+
+ public int getMaxWait() {
+ return getPoolProperties().getMaxWait();
+ }
+
+ public int getMinEvictableIdleTimeMillis() {
+ return getPoolProperties().getMinEvictableIdleTimeMillis();
+ }
+
+ public int getMinIdle() {
+ return getPoolProperties().getMinIdle();
+ }
+
+ public long getMaxAge() {
+ return getPoolProperties().getMaxAge();
+ }
+
+ public String getName() {
+ return this.getPoolName();
+ }
+
+ public int getNumTestsPerEvictionRun() {
+ return getPoolProperties().getNumTestsPerEvictionRun();
+ }
+
+ /**
+ * @return DOES NOT RETURN THE PASSWORD, IT WOULD SHOW UP IN JMX
+ */
+ public String getPassword() {
+ return "Password not available as DataSource/JMX operation.";
+ }
+
+ public int getRemoveAbandonedTimeout() {
+ return getPoolProperties().getRemoveAbandonedTimeout();
+ }
+
+
+ public int getTimeBetweenEvictionRunsMillis() {
+ return getPoolProperties().getTimeBetweenEvictionRunsMillis();
+ }
+
+ public String getUrl() {
+ return getPoolProperties().getUrl();
+ }
+
+ public String getUsername() {
+ return getPoolProperties().getUsername();
+ }
+
+ public long getValidationInterval() {
+ return getPoolProperties().getValidationInterval();
+ }
+
+ public String getValidationQuery() {
+ return getPoolProperties().getValidationQuery();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public String getValidatorClassName() {
+ return getPoolProperties().getValidatorClassName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public Validator getValidator() {
+ return getPoolProperties().getValidator();
+ }
+
+ public boolean isAccessToUnderlyingConnectionAllowed() {
+ return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
+ }
+
+ public Boolean isDefaultAutoCommit() {
+ return getPoolProperties().isDefaultAutoCommit();
+ }
+
+ public Boolean isDefaultReadOnly() {
+ return getPoolProperties().isDefaultReadOnly();
+ }
+
+ public boolean isLogAbandoned() {
+ return getPoolProperties().isLogAbandoned();
+ }
+
+ public boolean isPoolSweeperEnabled() {
+ return getPoolProperties().isPoolSweeperEnabled();
+ }
+
+ public boolean isRemoveAbandoned() {
+ return getPoolProperties().isRemoveAbandoned();
+ }
+
+ public int getAbandonWhenPercentageFull() {
+ return getPoolProperties().getAbandonWhenPercentageFull();
+ }
+
+ public boolean isTestOnBorrow() {
+ return getPoolProperties().isTestOnBorrow();
+ }
+
+ public boolean isTestOnConnect() {
+ return getPoolProperties().isTestOnConnect();
+ }
+
+ public boolean isTestOnReturn() {
+ return getPoolProperties().isTestOnReturn();
+ }
+
+ public boolean isTestWhileIdle() {
+ return getPoolProperties().isTestWhileIdle();
+ }
+
+
+ public Boolean getDefaultAutoCommit() {
+ return getPoolProperties().getDefaultAutoCommit();
+ }
+
+ public Boolean getDefaultReadOnly() {
+ return getPoolProperties().getDefaultReadOnly();
+ }
+
+ public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
+ return getPoolProperties().getJdbcInterceptorsAsArray();
+ }
+
+ public boolean getUseLock() {
+ return getPoolProperties().getUseLock();
+ }
+
+ public boolean isFairQueue() {
+ return getPoolProperties().isFairQueue();
+ }
+
+ public boolean isJmxEnabled() {
+ return getPoolProperties().isJmxEnabled();
+ }
+
+ public boolean isUseEquals() {
+ return getPoolProperties().isUseEquals();
+ }
+
+ public void setAbandonWhenPercentageFull(int percentage) {
+ getPoolProperties().setAbandonWhenPercentageFull(percentage);
+ }
+
+ public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
+ getPoolProperties().setAccessToUnderlyingConnectionAllowed(accessToUnderlyingConnectionAllowed);
+ }
+
+ public void setDbProperties(Properties dbProperties) {
+ getPoolProperties().setDbProperties(dbProperties);
+ }
+
+ public void setDefaultReadOnly(Boolean defaultReadOnly) {
+ getPoolProperties().setDefaultReadOnly(defaultReadOnly);
+ }
+
+ public void setMaxAge(long maxAge) {
+ getPoolProperties().setMaxAge(maxAge);
+ }
+
+ public void setName(String name) {
+ getPoolProperties().setName(name);
+ }
+
+ public String getPoolName() {
+ return getPoolProperties().getName();
+ }
+
+
+ public void setConnectionProperties(String connectionProperties) {
+ getPoolProperties().setConnectionProperties(connectionProperties);
+
+ }
+
+ public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
+ getPoolProperties().setDefaultAutoCommit(defaultAutoCommit);
+ }
+
+ public void setDefaultCatalog(String defaultCatalog) {
+ getPoolProperties().setDefaultCatalog(defaultCatalog);
+ }
+
+ public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
+ getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
+ }
+
+ public void setDriverClassName(String driverClassName) {
+ getPoolProperties().setDriverClassName(driverClassName);
+ }
+
+
+ public void setFairQueue(boolean fairQueue) {
+ getPoolProperties().setFairQueue(fairQueue);
+ }
+
+
+ public void setInitialSize(int initialSize) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setInitSQL(String initSQL) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setJdbcInterceptors(String jdbcInterceptors) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setJmxEnabled(boolean jmxEnabled) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setLogAbandoned(boolean logAbandoned) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setMaxActive(int maxActive) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setMaxIdle(int maxIdle) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setMaxWait(int maxWait) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setMinIdle(int minIdle) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setPassword(String password) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setRemoveAbandoned(boolean removeAbandoned) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setTestOnBorrow(boolean testOnBorrow) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setTestOnConnect(boolean testOnConnect) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setTestOnReturn(boolean testOnReturn) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setTestWhileIdle(boolean testWhileIdle) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setUrl(String url) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setUseEquals(boolean useEquals) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setUseLock(boolean useLock) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setUsername(String username) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setValidationInterval(long validationInterval) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void setValidationQuery(String validationQuery) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setValidatorClassName(String className) {
+ getPoolProperties().setValidatorClassName(className);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public int getSuspectTimeout() {
+ return getPoolProperties().getSuspectTimeout();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+
+ public void setSuspectTimeout(int seconds) {
+ //no op
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDataSource(Object ds) {
+ getPoolProperties().setDataSource(ds);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getDataSource() {
+ return getPoolProperties().getDataSource();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDataSourceJNDI(String jndiDS) {
+ //noop
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getDataSourceJNDI() {
+ return getPoolProperties().getDataSourceJNDI();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isAlternateUsernameAllowed() {
+ return getPoolProperties().isAlternateUsernameAllowed();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
+ //noop
+ }
+
+}
--- /dev/null
+/* 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 org.apache.tomcat.jdbc.pool.PoolConfiguration;
+
+public interface ConnectionPoolMBean extends PoolConfiguration {
+
+ //=================================================================
+ // POOL STATS
+ //=================================================================
+
+ public int getSize();
+
+ public int getIdle();
+
+ public int getActive();
+
+ public boolean isPoolSweeperEnabled();
+
+ public int getNumIdle();
+
+ public int getNumActive();
+
+ public int getWaitCount();
+
+ //=================================================================
+ // POOL OPERATIONS
+ //=================================================================
+ public void checkIdle();
+
+ public void checkAbandoned();
+
+ public void testIdle();
+
+ //=================================================================
+ // POOL NOTIFICATIONS
+ //=================================================================
+
+
+}
--- /dev/null
+<?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.
+-->
+<mbeans-descriptors>
+
+ <mbean name="TomcatJDBCPool"
+ description="Provides per diagnostic metrics and notifications for JDBC operations"
+ domain="tomcat"
+ group="jdbc"
+ type="org.apache.tomcat.jdbc.pool.DataSource">
+
+ <attribute name="className"
+ description="Fully qualified class name of the managed object"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="size"
+ description="The number of established connections in the pool, idle and in use"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="idle"
+ description="The number of established connections in the pool that are idle"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="numIdle"
+ description="Same as the idle attribute"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="active"
+ description="The number of established connections in the pool that are in use"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="numActive"
+ description="Same as the active attribute"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="poolSweeperEnabled"
+ description="Returns true if the pool has a background thread running"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="url"
+ description="The JDBC url for this connection pool"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="driverClassName"
+ description="The JDBC driver class for this connection pool"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="defaultAutoCommit"
+ description="The JDBC auto commit setting for new connections"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="defaultReadOnly"
+ description="The JDBC read only setting for new connections"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="defaultTransactionIsolation"
+ description="The JDBC transaction isolation setting for new connections"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="connectionProperties"
+ description="The connection properties that will be set for new connections. Format of the string will be [propertyName=property;]*"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="defaultCatalog"
+ description="The JDBC transaction isolation setting for new connections"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="initialSize"
+ description="The number of connections opened at pool startup"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="maxActive"
+ description="The maximum number of open connections"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="maxIdle"
+ description="The max number of idle connections"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="minIdle"
+ description="The minimum number of open connections"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="maxWait"
+ description="The time to wait in milliseconds before a SQLException is thrown when a connection is requested"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="validationQuery"
+ description="The query to run during validation"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="testOnBorrow"
+ description="True if validation happens when a connection is requested"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="testOnReturn"
+ description="True if validation happens when a connection is returned"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="testWhileIdle"
+ description="True if validation happens when a connection is not in use (idle)"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="timeBetweenEvictionRunsMillis"
+ description="Sleep time for background thread in between pool checks"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="numTestsPerEvictionRun"
+ description="Not in use"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="minEvictableIdleTimeMillis"
+ description="Minimum amount of time a connection stays idle before it is evicted"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="accessToUnderlyingConnectionAllowed"
+ description="Returns true if one can retrieve the actual JDBC connection"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="removeAbandoned"
+ description="Returns true if connection in use can be timed out"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="removeAbandonedTimeout"
+ description="Timeout in seconds for connections in use"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+ <attribute name="logAbandoned"
+ description="If true, stack trace will be recorded and printed out for timed out connection"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="loginTimeout"
+ description="Not in use"
+ type="java.lang.Integer"
+ writeable="false"/>
+
+
+ <attribute name="name"
+ description="The name of the connection pool, will be used in the ObjectName of the actual pool"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="password"
+ description="For security purposes,this doesn't return anything"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="username"
+ description="The username used to open connections"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="validationInterval"
+ description="If larger than zero than validation will only occur after the interval milliseconds has passed"
+ type="java.lang.Long"
+ writeable="false"/>
+
+ <attribute name="initSQL"
+ description="A SQL executed once per connection, when it is established"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <attribute name="testOnConnect"
+ description="Validate connection after connection has been established"
+ type="java.lang.Boolean"
+ is="true"
+ writeable="false"/>
+
+ <attribute name="jdbcInterceptors"
+ description="The interceptors configured for this pool"
+ type="java.lang.String"
+ writeable="false"/>
+
+ <operation name="checkIdle"
+ description="forces a check of idle connections"
+ impact="ACTION"
+ returnType="void" />
+
+ <operation name="checkAbandoned"
+ description="forces a check of abandoned connections"
+ impact="ACTION"
+ returnType="void" />
+
+ <operation name="testIdle"
+ description="forces a validation of abandoned connections"
+ impact="ACTION"
+ returnType="void" />
+ </mbean>
+
+</mbeans-descriptors>
--- /dev/null
+/*
+ * 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.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
+
+public class TestInterceptor extends JdbcInterceptor {
+ public static boolean poolstarted = false;
+ public static boolean poolclosed = false;
+ public static AtomicInteger instancecount = new AtomicInteger(0);
+
+ @Override
+ public void poolClosed(ConnectionPool pool) {
+ // TODO Auto-generated method stub
+ super.poolClosed(pool);
+ poolclosed = true;
+ }
+
+ @Override
+ public void poolStarted(ConnectionPool pool) {
+ super.poolStarted(pool);
+ poolstarted = true;
+ }
+
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setProperties(Map<String, InterceptorProperty> properties) {
+ instancecount.incrementAndGet();
+ super.setProperties(properties);
+ }
+
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer;
+
+public class AbandonPercentageTest extends DefaultTestCase {
+
+ public AbandonPercentageTest(String name) {
+ super(name);
+ }
+
+ public void testDefaultAbandon() throws Exception {
+ this.init();
+ this.datasource.setMaxActive(100);
+ this.datasource.setMaxIdle(100);
+ this.datasource.setInitialSize(0);
+ this.datasource.getPoolProperties().setAbandonWhenPercentageFull(0);
+ this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100);
+ this.datasource.getPoolProperties().setRemoveAbandoned(true);
+ this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
+ Connection con = datasource.getConnection();
+ assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
+ Thread.sleep(2000);
+ assertEquals("Number of connections active/busy should be 0",0,datasource.getPool().getActive());
+ con.close();
+ }
+
+ public void testMaxedOutAbandon() throws Exception {
+ int size = 100;
+ this.init();
+ this.datasource.setMaxActive(size);
+ this.datasource.setMaxIdle(size);
+ this.datasource.setInitialSize(0);
+ this.datasource.getPoolProperties().setAbandonWhenPercentageFull(100);
+ this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100);
+ this.datasource.getPoolProperties().setRemoveAbandoned(true);
+ this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
+ Connection con = datasource.getConnection();
+ assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
+ Thread.sleep(2000);
+ assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
+ con.close();
+ }
+
+ public void testResetConnection() throws Exception {
+ int size = 1;
+ this.init();
+ this.datasource.setMaxActive(size);
+ this.datasource.setMaxIdle(size);
+ this.datasource.setInitialSize(0);
+ this.datasource.getPoolProperties().setAbandonWhenPercentageFull(100);
+ this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100);
+ this.datasource.getPoolProperties().setRemoveAbandoned(true);
+ this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
+ this.datasource.getPoolProperties().setJdbcInterceptors(ResetAbandonedTimer.class.getName());
+ Connection con = datasource.getConnection();
+ assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
+ for (int i=0; i<20; i++) {
+ Thread.sleep(200);
+ con.isClosed();
+ }
+ assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
+ con.close();
+ }
+
+ public void testHalfway() throws Exception {
+ int size = 100;
+ this.init();
+ this.datasource.setMaxActive(size);
+ this.datasource.setMaxIdle(size);
+ this.datasource.setInitialSize(0);
+ this.datasource.getPoolProperties().setAbandonWhenPercentageFull(50);
+ this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(500);
+ this.datasource.getPoolProperties().setRemoveAbandoned(true);
+ this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
+ Connection[] con = new Connection[size];
+ con[0] = datasource.getConnection();
+ assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
+ for (int i=1; i<25; i++) {
+ con[i] = datasource.getConnection();
+ }
+ assertEquals("Number of connections active/busy should be 25",25,datasource.getPool().getActive());
+ Thread.sleep(2500);
+ assertEquals("Number of connections active/busy should be 25",25,datasource.getPool().getActive());
+ this.datasource.getPoolProperties().setRemoveAbandonedTimeout(100);
+ for (int i=25; i<con.length; i++) {
+ con[i] = datasource.getConnection();
+ }
+ int active = datasource.getPool().getActive();
+ System.out.println("Active:"+active);
+ assertEquals("Number of connections active/busy should be "+con.length,con.length,datasource.getPool().getActive());
+ this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
+ Thread.sleep(2500);
+ this.assertTrue("Number of connections should be less than 50.", (datasource.getPool().getActive()<50));
+ this.datasource.getPoolProperties().setAbandonWhenPercentageFull(0);
+ Thread.sleep(2500);
+ assertEquals("Number of connections active/busy should be "+0,0,datasource.getPool().getActive());
+ }
+}
--- /dev/null
+/*
+ * 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.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.sql.PooledConnection;
+
+import org.apache.tomcat.jdbc.test.driver.Connection;
+import org.apache.tomcat.jdbc.test.driver.Driver;
+
+
+public class AlternateUsernameTest extends DefaultTestCase {
+
+ private static final int iterations = 500000; //(new Random(System.currentTimeMillis())).nextInt(1000000)+100000;
+ public AlternateUsernameTest(String name) {
+ super(name);
+ }
+ public void testUsernameCompare() throws Exception {
+ testUsername(true);
+ }
+
+ private void testUsername(boolean allowUsernameChange) throws Exception {
+ long start = System.currentTimeMillis();
+ int withoutuser =10;
+ int withuser = withoutuser;
+ this.init();
+ this.datasource.setMaxActive(withuser+withoutuser);
+ this.datasource.setDriverClassName(Driver.class.getName());
+ this.datasource.setUrl("jdbc:tomcat:test");
+ this.datasource.setAlternateUsernameAllowed(allowUsernameChange);
+ this.datasource.getConnection().close();
+
+ TestRunner[] runners = new TestRunner[withuser+withoutuser];
+ for (int i=0; i<withuser; i++) {
+ TestRunner with = new TestRunner("foo","bar",datasource.getPoolProperties().getUsername(),datasource.getPoolProperties().getPassword());
+ TestRunner without = new TestRunner(null,null,datasource.getPoolProperties().getUsername(),datasource.getPoolProperties().getPassword());
+ runners[i] = allowUsernameChange?with:without;
+ runners[i+withuser] = without;
+ }
+ ExecutorService svc = Executors.newFixedThreadPool(withuser+withoutuser);
+ List<Future<TestResult>> results = svc.invokeAll(Arrays.asList(runners));
+ int failures = 0;
+ int total = 0;
+ for (int i=0; i<withuser; i++) {
+ failures += results.get(i).get().failures;
+ total+=results.get(i).get().iterations;
+ failures += results.get(i+withuser).get().failures;
+ total+=results.get(i+withuser).get().iterations;
+ }
+ long stop = System.currentTimeMillis();
+ assertEquals("Nr of failures was:"+failures,0, failures);
+ svc.shutdownNow();
+ this.datasource.close();
+ System.out.println("Nr of connect() calls:"+Driver.connectCount.get());
+ System.out.println("Nr of disconnect() calls:"+Driver.disconnectCount.get());
+ System.out.println("Nr of iterations:"+total+" over "+(stop-start)+ " ms.");
+
+ }
+
+ public void testUsernameCompareAgain() throws Exception {
+ testUsernameCompare();
+ }
+
+ public void testUsernameCompareNotAllowed() throws Exception {
+ testUsername(false);
+ }
+
+ public static class TestResult {
+ public int iterations;
+ public int failures;
+ public String lastMessage;
+ }
+
+ public class TestRunner implements Callable<TestResult> {
+ String username;
+ String password;
+ volatile boolean done = false;
+ TestResult result = null;
+ boolean useuser = true;
+
+ public TestRunner(String user, String pass, String guser, String gpass) {
+ username = user==null?guser : user;
+ password = pass==null?gpass : pass;
+ useuser = user!=null;
+ }
+
+ public TestResult call() {
+ TestResult test = new TestResult();
+ PooledConnection pcon = null;
+ for (int i=0; (!done) && (i<iterations); i++) {
+ test.iterations = i+1;
+ try {
+
+
+ pcon = useuser ? (PooledConnection)AlternateUsernameTest.this.datasource.getConnection(username, password) :
+ (PooledConnection)AlternateUsernameTest.this.datasource.getConnection();
+
+ Connection con = (Connection)pcon.getConnection();
+
+ assertTrue("Username mismatch: Requested User:"+username+" Actual user:"+con.getUsername(), con.getUsername().equals(username));
+ assertTrue("Password mismatch: Requested Password:"+password+" Actual password:"+con.getPassword(), con.getPassword().equals(password));
+ }catch (SQLException x) {
+ test.failures++;
+ test.lastMessage = x.getMessage();
+ done = true;
+ x.printStackTrace();
+ }catch (Exception x) {
+ test.failures++;
+ test.lastMessage = x.getMessage();
+ x.printStackTrace();
+ } finally {
+ if (pcon!=null) {
+ try {pcon.close(); }catch (Exception ignore) {}
+ pcon = null;
+ }
+ }
+ }
+ done = true;
+ result = test;
+ return result;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.tomcat.jdbc.pool.DataSourceProxy;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class Async0IdleTestBug50477 extends DefaultTestCase {
+ public Async0IdleTestBug50477(String name) {
+ super(name);
+ }
+
+
+ public void testAsync0Idle0Size() throws Exception {
+ System.out.println("[testPoolThreads20Connections10FairAsync] Starting fairness - Tomcat JDBC - Fair - Async");
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.datasource.getPoolProperties().setFairQueue(true);
+ this.datasource.getPoolProperties().setInitialSize(0);
+ try {
+ Future<Connection> cf = ((DataSourceProxy)datasource).getConnectionAsync();
+ Connection con = cf.get(5, TimeUnit.SECONDS);
+ }finally {
+ tearDown();
+ }
+ }
+}
+
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.sql.SQLException;
+
+public class BorrowWaitTest extends DefaultTestCase {
+
+ public BorrowWaitTest(String name) {
+ super(name);
+ }
+
+ public void testWaitTime() throws Exception {
+ int wait = 10000;
+ this.init();
+ this.datasource.setMaxActive(1);
+ this.datasource.setMaxWait(wait);
+ Connection con = datasource.getConnection();
+ try {
+ Connection con2 = datasource.getConnection();
+ assertFalse("This should not happen, connection should be unavailable.",true);
+ con2.close();
+ }catch (SQLException x) {
+ long delta = System.currentTimeMillis();
+ boolean inrange = Math.abs(wait-delta) < 1000;
+ assertTrue("Connection should have been acquired within +/- 1 second.",true);
+ }
+ con.close();
+ }
+
+ public void testWaitTimeInfinite() throws Exception {
+ if(true){
+ System.err.println("testWaitTimeInfinite() test is disabled.");
+ return;//this would lock up the test suite
+ }
+ int wait = -1;
+ this.init();
+ this.datasource.setMaxActive(1);
+ this.datasource.setMaxWait(wait);
+ Connection con = datasource.getConnection();
+ long start = System.currentTimeMillis();
+ try {
+ Connection con2 = datasource.getConnection();
+ assertFalse("This should not happen, connection should be unavailable.",true);
+ }catch (SQLException x) {
+ long delta = System.currentTimeMillis();
+ boolean inrange = Math.abs(wait-delta) < 1000;
+ assertTrue("Connection should have been acquired within +/- 1 second.",true);
+ }
+ con.close();
+ }
+
+
+}
--- /dev/null
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.jdbc.test;\r
+\r
+import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;\r
+\r
+public class Bug50571 extends DefaultTestCase{\r
+ \r
+ public Bug50571(String name) {\r
+ super(name);\r
+ }\r
+ \r
+ @Override\r
+ public void setUp() throws Exception {\r
+ super.setUp();\r
+ this.datasource.setUrl("jdbc:h2:~/.h2/test;QUERY_TIMEOUT=0;DB_CLOSE_ON_EXIT=FALSE");\r
+ this.datasource.setJdbcInterceptors(ConnectionState.class.getName());\r
+ this.datasource.setDefaultTransactionIsolation(-55);\r
+ this.datasource.setInitialSize(1);\r
+ }\r
+ \r
+ public void testBug50571() throws Exception {\r
+ this.datasource.getConnection().close();\r
+ }\r
+}\r
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.util.concurrent.Future;
+
+public class Bug50805 extends DefaultTestCase {
+ public Bug50805(String name) {
+ super(name);
+ }
+
+ public void test50805() throws Exception {
+ init();
+ this.datasource.setInitialSize(0);
+ this.datasource.setMaxActive(10);
+ this.datasource.setMinIdle(1);
+
+ assertEquals("Current size should be 0.", 0, this.datasource.getSize());
+
+ this.datasource.getConnection().close();
+
+ assertEquals("Current size should be 1.", 1, this.datasource.getSize());
+ assertEquals("Idle size should be 1.", 1, this.datasource.getIdle());
+ assertEquals("Busy size should be 0.", 0, this.datasource.getActive());
+
+ Future<Connection> fc = this.datasource.getConnectionAsync();
+
+ Connection con = fc.get();
+
+ assertEquals("Current size should be 1.", 1, this.datasource.getSize());
+ assertEquals("Idle size should be 0.", 0, this.datasource.getIdle());
+ assertEquals("Busy size should be 1.", 1, this.datasource.getActive());
+
+ con.close();
+ assertEquals("Current size should be 1.", 1, this.datasource.getSize());
+ assertEquals("Idle size should be 1.", 1, this.datasource.getIdle());
+ assertEquals("Busy size should be 0.", 0, this.datasource.getActive());
+ }
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.sql.Statement;
+import java.sql.ResultSet;
+
+import javax.sql.DataSource;
+
+
+/**
+ * @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.datasource.getPoolProperties().setFairQueue(false);
+ 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 = 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 testPoolThreads10Connections10Fair() throws Exception {
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.datasource.getPoolProperties().setFairQueue(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-"+i);
+ t.d = this.datasource;
+ t.start();
+ }
+ latch.await();
+ long delta = System.currentTimeMillis() - start;
+ System.out.println("[testPoolThreads10Connections10Fair]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+ tearDown();
+ }
+
+// public void testC3P0Threads10Connections10() throws Exception {
+// init();
+// this.datasource.getPoolProperties().setMaxActive(10);
+// this.threadcount = 10;
+// this.transferPropertiesToC3P0();
+// this.c3p0Datasource.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 = this.c3p0Datasource;
+// t.start();
+// }
+// latch.await();
+// long delta = System.currentTimeMillis() - start;
+// System.out.println("[testC3P0Threads10Connections10]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.datasource.getPoolProperties().setFairQueue(false);
+ 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 = 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 testPoolThreads20Connections10Fair() throws Exception {
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.datasource.getPoolProperties().setFairQueue(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-"+i);
+ t.d = this.datasource;
+ t.start();
+ }
+ latch.await();
+ long delta = System.currentTimeMillis() - start;
+ System.out.println("[testPoolThreads20Connections10Fair]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+ tearDown();
+ }
+
+// public void testC3P0Threads20Connections10() throws Exception {
+// init();
+// this.datasource.getPoolProperties().setMaxActive(10);
+// this.threadcount = 20;
+// this.transferPropertiesToC3P0();
+// this.c3p0Datasource.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 = this.c3p0Datasource;
+// t.start();
+// }
+// latch.await();
+// long delta = System.currentTimeMillis() - start;
+// System.out.println("[testC3P0Threads20Connections10]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+// tearDown();
+// }
+
+ public void testDBCPThreads10Connections10Validate() throws Exception {
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ 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().setTestOnBorrow(true);
+ this.datasource.getPoolProperties().setFairQueue(false);
+ 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 = 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 testPoolThreads10Connections10ValidateFair() throws Exception {
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.datasource.getPoolProperties().setTestOnBorrow(true);
+ this.datasource.getPoolProperties().setFairQueue(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 = this.datasource;
+ t.start();
+ }
+ latch.await();
+ long delta = System.currentTimeMillis() - start;
+ System.out.println("[testPoolThreads10Connections10ValidateFair]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+ tearDown();
+ }
+
+// public void testC3P0Threads10Connections10Validate() throws Exception {
+// init();
+// this.datasource.getPoolProperties().setMaxActive(10);
+// this.datasource.getPoolProperties().setTestOnBorrow(true);
+// this.threadcount = 10;
+// this.transferPropertiesToC3P0();
+// this.c3p0Datasource.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 = this.c3p0Datasource;
+// t.start();
+// }
+// latch.await();
+// long delta = System.currentTimeMillis() - start;
+// System.out.println("[testC3P0Threads10Connections10Validate]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+// tearDown();
+// }
+
+ public void testDBCPThreads20Connections10Validate() throws Exception {
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ 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().setTestOnBorrow(true);
+ this.datasource.getPoolProperties().setFairQueue(false);
+ 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 = 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 void testPoolThreads10Connections20ValidateFair() throws Exception {
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.datasource.getPoolProperties().setTestOnBorrow(true);
+ this.datasource.getPoolProperties().setFairQueue(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 = this.datasource;
+ t.start();
+ }
+ latch.await();
+ long delta = System.currentTimeMillis() - start;
+ System.out.println("[testPoolThreads20Connections10ValidateFair]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+ tearDown();
+ }
+
+// public void testC3P0Threads10Connections20Validate() throws Exception {
+// init();
+// this.datasource.getPoolProperties().setMaxActive(10);
+// this.datasource.getPoolProperties().setTestOnBorrow(true);
+// this.threadcount = 20;
+// this.transferPropertiesToC3P0();
+// this.c3p0Datasource.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 = this.c3p0Datasource;
+// t.start();
+// }
+// latch.await();
+// long delta = System.currentTimeMillis() - start;
+// System.out.println("[testC3P0Threads10Connections20Validate]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+// tearDown();
+// }
+
+ public class TestThread extends Thread {
+ protected DataSource d;
+ protected String query = null;
+ @Override
+ 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++;
+ if (query!=null) {
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery(query);
+ while (rs.next()) {
+ }
+ rs.close();
+ st.close();
+ }
+ } 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:"+(max/1000f/1000f)+" ms."+
+ "\n\tTotal time to retrieve connection:"+(totalmax/1000f/1000f)+" ms."+
+ "\n\tAverage time to retrieve connection:"+(totalmax/1000f/1000f)/nroffetch+" ms."+
+ "\n\tMax time to close connection:"+(cmax/1000f/1000f)+" ms."+
+ "\n\tTotal time to close connection:"+(totalcmax/1000f/1000f)+" ms."+
+ "\n\tAverage time to close connection:"+(totalcmax/1000f/1000f)/nroffetch+" ms."+
+ "\n\tRun time:"+(totalruntime/1000f/1000f)+" ms."+
+ "\n\tNr of fetch:"+nroffetch);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.Future;
+import java.util.concurrent.TimeUnit;
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.ResultSet;
+
+import javax.sql.DataSource;
+
+import org.apache.tomcat.jdbc.pool.DataSourceProxy;
+import org.apache.tomcat.jdbc.test.driver.Driver;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class ConnectCountTest extends DefaultTestCase {
+ public ConnectCountTest(String name) {
+ super(name);
+ }
+
+ protected boolean run = true;
+ protected long sleep = Long.getLong("sleep", 10);
+ protected long complete = Long.getLong("complete",20000);
+ protected boolean printthread = Boolean.getBoolean("printthread");
+ CountDownLatch latch = null;
+
+
+ @Override
+ public org.apache.tomcat.jdbc.pool.DataSource createDefaultDataSource() {
+ // TODO Auto-generated method stub
+ org.apache.tomcat.jdbc.pool.DataSource ds = super.createDefaultDataSource();
+ ds.getPoolProperties().setDriverClassName(Driver.class.getName());
+ ds.getPoolProperties().setUrl(Driver.url);
+ ds.getPoolProperties().setInitialSize(0);
+ ds.getPoolProperties().setMaxIdle(10);
+ ds.getPoolProperties().setMinIdle(10);
+ ds.getPoolProperties().setMaxActive(10);
+ return ds;
+ }
+
+
+ @Override
+ protected void tearDown() throws Exception {
+ Driver.reset();
+ super.tearDown();
+ }
+
+
+ protected void printThreadResults(TestThread[] threads, String name, int active, int expected) {
+ long minfetch = Long.MAX_VALUE, maxfetch = Long.MIN_VALUE, totalfetch = 0;
+ long maxwait = 0, minwait = Long.MAX_VALUE, averagewait = 0, totalwait = 0;
+ float avgfetch = 0;
+ for (int i=0; i<threads.length; i++) {
+ TestThread t = threads[i];
+ totalfetch += t.nroffetch;
+ totalwait += t.totalwait;
+ maxwait = Math.max(maxwait,t.maxwait);
+ minwait = Math.min(minwait, t.minwait);
+ minfetch = Math.min(minfetch, t.nroffetch);
+ maxfetch = Math.max(maxfetch, t.nroffetch);
+ if (ConnectCountTest.this.printthread)
+ System.out.println(t.getName()+" : Nr-of-fetch:"+t.nroffetch+ " Max fetch Time:"+(((float)t.maxwait)/1000000f)+"ms. :Max close time:"+(((float)t.cmax)/1000000f)+"ms.");
+ }
+ System.out.println("["+name+"] Max fetch:"+(maxfetch)+" Min fetch:"+(minfetch)+" Average fetch:"+
+ (((float)totalfetch))/(float)threads.length);
+ System.out.println("["+name+"] Max wait:"+(((float)maxwait)/1000000f)+"ms. Min wait:"+(((float)minwait)/1000000f)+"ms. Average wait:"+(((((float)totalwait))/(float)totalfetch)/1000000f)+" ms.");
+ System.out.println("["+name+"] Max active:"+active+" Expected Active:"+expected);
+
+
+ }
+
+ public void testDBCPThreads20Connections10() throws Exception {
+ System.out.println("[testDBCPThreads20Connections10] Starting fairness - DBCP");
+ this.threadcount = 20;
+ init();
+ this.transferProperties();
+ this.tDatasource.getConnection().close();
+ latch = new CountDownLatch(threadcount);
+ long start = System.currentTimeMillis();
+ TestThread[] threads = new TestThread[threadcount];
+ for (int i=0; i<threadcount; i++) {
+ threads[i] = new TestThread();
+ threads[i].setName("tomcat-dbcp-"+i);
+ threads[i].d = this.tDatasource;
+
+ }
+ for (int i=0; i<threadcount; i++) {
+ threads[i].start();
+ }
+ if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+ System.out.println("Latch timed out.");
+ }
+ this.run = false;
+ long delta = System.currentTimeMillis() - start;
+ printThreadResults(threads,"testDBCPThreads20Connections10",Driver.connectCount.get(),10);
+ tearDown();
+ }
+
+ public void testPoolThreads20Connections10() throws Exception {
+ System.out.println("[testPoolThreads20Connections10] Starting fairness - Tomcat JDBC - Non Fair");
+ init();
+ this.threadcount = 20;
+ this.transferProperties();
+ this.datasource.getConnection().close();
+ latch = new CountDownLatch(threadcount);
+ long start = System.currentTimeMillis();
+ TestThread[] threads = new TestThread[threadcount];
+ for (int i=0; i<threadcount; i++) {
+ threads[i] = new TestThread();
+ threads[i].setName("tomcat-pool-"+i);
+ threads[i].d = this.datasource;
+
+ }
+ for (int i=0; i<threadcount; i++) {
+ threads[i].start();
+ }
+ if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+ System.out.println("Latch timed out.");
+ }
+ this.run = false;
+ long delta = System.currentTimeMillis() - start;
+ printThreadResults(threads,"testPoolThreads20Connections10",Driver.connectCount.get(),10);
+ tearDown();
+
+ }
+
+ public void testPoolThreads20Connections10Fair() throws Exception {
+ System.out.println("[testPoolThreads20Connections10Fair] Starting fairness - Tomcat JDBC - Fair");
+ init();
+ this.threadcount = 20;
+ this.datasource.getPoolProperties().setFairQueue(true);
+ this.transferProperties();
+ this.datasource.getConnection().close();
+ latch = new CountDownLatch(threadcount);
+ long start = System.currentTimeMillis();
+ TestThread[] threads = new TestThread[threadcount];
+ for (int i=0; i<threadcount; i++) {
+ threads[i] = new TestThread();
+ threads[i].setName("tomcat-pool-"+i);
+ threads[i].d = this.datasource;
+
+ }
+ for (int i=0; i<threadcount; i++) {
+ threads[i].start();
+ }
+ if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+ System.out.println("Latch timed out.");
+ }
+ this.run = false;
+ long delta = System.currentTimeMillis() - start;
+ printThreadResults(threads,"testPoolThreads20Connections10Fair",Driver.connectCount.get(),10);
+ tearDown();
+ }
+
+ public void testPoolThreads20Connections10FairAsync() throws Exception {
+ System.out.println("[testPoolThreads20Connections10FairAsync] Starting fairness - Tomcat JDBC - Fair - Async");
+ init();
+ this.threadcount = 20;
+ this.datasource.getPoolProperties().setFairQueue(true);
+ this.datasource.getPoolProperties().setInitialSize(this.datasource.getPoolProperties().getMaxActive());
+ this.transferProperties();
+ this.datasource.getConnection().close();
+ latch = new CountDownLatch(threadcount);
+ long start = System.currentTimeMillis();
+ TestThread[] threads = new TestThread[threadcount];
+ for (int i=0; i<threadcount; i++) {
+ threads[i] = new TestThread();
+ threads[i].setName("tomcat-pool-"+i);
+ threads[i].async = true;
+ threads[i].d = this.datasource;
+
+ }
+ for (int i=0; i<threadcount; i++) {
+ threads[i].start();
+ }
+ if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+ System.out.println("Latch timed out.");
+ }
+ this.run = false;
+ long delta = System.currentTimeMillis() - start;
+ printThreadResults(threads,"testPoolThreads20Connections10FairAsync",Driver.connectCount.get(),10);
+ tearDown();
+ }
+
+// public void testC3P0Threads20Connections10() throws Exception {
+// System.out.println("[testC3P0Threads20Connections10] Starting fairness - C3P0");
+// init();
+// this.threadcount = 20;
+// this.transferPropertiesToC3P0();
+// this.datasource.getConnection().close();
+// latch = new CountDownLatch(threadcount);
+// long start = System.currentTimeMillis();
+// TestThread[] threads = new TestThread[threadcount];
+// for (int i=0; i<threadcount; i++) {
+// threads[i] = new TestThread();
+// threads[i].setName("tomcat-pool-"+i);
+// threads[i].d = this.c3p0Datasource;
+//
+// }
+// for (int i=0; i<threadcount; i++) {
+// threads[i].start();
+// }
+// if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+// System.out.println("Latch timed out.");
+// }
+// this.run = false;
+// long delta = System.currentTimeMillis() - start;
+// printThreadResults(threads,"testC3P0Threads20Connections10",Driver.connectCount.get(),10);
+// tearDown();
+//
+// }
+
+
+ public class TestThread extends Thread {
+ protected DataSource d;
+ protected String query = null;
+ protected long sleep = 10;
+ protected boolean async = false;
+ long minwait = Long.MAX_VALUE, maxwait = -1, totalwait=0, totalcmax=0, cmax = -1, nroffetch = 0, totalruntime = 0;
+ @Override
+ public void run() {
+ try {
+ long now = System.currentTimeMillis();
+ while (ConnectCountTest.this.run) {
+ if ((System.currentTimeMillis()-now)>=ConnectCountTest.this.complete) break;
+ long start = System.nanoTime();
+ Connection con = null;
+ try {
+ if (async) {
+ Future<Connection> cf = ((DataSourceProxy)d).getConnectionAsync();
+ con = cf.get();
+ } else {
+ con = d.getConnection();
+ }
+ long delta = System.nanoTime() - start;
+ totalwait += delta;
+ maxwait = Math.max(delta, maxwait);
+ minwait = Math.min(delta, minwait);
+ nroffetch++;
+ if (query!=null) {
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery(query);
+ while (rs.next()) {
+ }
+ rs.close();
+ st.close();
+ }
+ try {
+ if (ConnectCountTest.this.sleep>0) sleep(ConnectCountTest.this.sleep);
+ } catch (InterruptedException x) {
+ interrupted();
+ }
+ } 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 {
+ ConnectCountTest.this.latch.countDown();
+ }
+ if (System.getProperty("print-thread-stats")!=null) {
+ System.out.println("["+getName()+"] "+
+ "\n\tMax time to retrieve connection:"+(((float)maxwait)/1000f/1000f)+" ms."+
+ "\n\tTotal time to retrieve connection:"+(((float)totalwait)/1000f/1000f)+" ms."+
+ "\n\tAverage time to retrieve connection:"+(((float)totalwait)/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);
+ }
+ }
+ }
+}
+
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.Statement;
+import java.util.Random;
+import java.sql.ResultSet;
+
+import org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer;
+
+public class CreateTestTable extends DefaultTestCase {
+
+ public static volatile boolean recreate = Boolean.getBoolean("recreate");
+
+ public CreateTestTable(String name) {
+ super(name);
+ }
+
+ public void testCreateTestTable() throws Exception {
+ this.init();
+ Connection con = datasource.getConnection();
+ Statement st = con.createStatement();
+ try {
+ st.execute("create table test(id int not null, val1 varchar(255), val2 varchar(255), val3 varchar(255), val4 varchar(255))");
+ }catch (Exception ignore) {}
+ st.close();
+ con.close();
+ }
+
+ public int testCheckData() throws Exception {
+ int count = 0;
+ String check = "select count (*) from test";
+ this.init();
+ Connection con = datasource.getConnection();
+ Statement st = con.createStatement();
+ try {
+ ResultSet rs = st.executeQuery(check);
+
+ if (rs.next())
+ count = rs.getInt(1);
+ rs.close();
+ st.close();
+ System.out.println("Count:"+count);
+ }catch (Exception ignore) {}
+ con.close();
+ return count;
+ }
+
+ public void testPopulateData() throws Exception {
+ int count = 100000;
+ int actual = testCheckData();
+ if (actual>=count) {
+ System.out.println("Test tables has "+actual+" rows of data. No need to populate.");
+ return;
+ }
+
+ datasource.setJdbcInterceptors(ResetAbandonedTimer.class.getName());
+ String insert = "insert into test values (?,?,?,?,?)";
+ this.init();
+ this.datasource.setRemoveAbandoned(false);
+ Connection con = datasource.getConnection();
+
+ boolean commit = con.getAutoCommit();
+ con.setAutoCommit(false);
+ if (recreate) {
+ Statement st = con.createStatement();
+ try {
+ st.execute("drop table test");
+ }catch (Exception ignore) {}
+ st.execute("create table test(id int not null, val1 varchar(255), val2 varchar(255), val3 varchar(255), val4 varchar(255))");
+ st.close();
+ }
+
+
+ PreparedStatement ps = con.prepareStatement(insert);
+ ps.setQueryTimeout(0);
+ for (int i=actual; i<count; i++) {
+ ps.setInt(1,i);
+ String s = getRandom();
+ ps.setString(2, s);
+ ps.setString(3, s);
+ ps.setString(4, s);
+ ps.setString(5, s);
+ ps.addBatch();
+ ps.clearParameters();
+ if ((i+1) % 1000 == 0) {
+ System.out.print(".");
+ }
+ if ((i+1) % 10000 == 0) {
+ System.out.print("\n"+(i+1));
+ ps.executeBatch();
+ ps.close();
+ con.commit();
+ ps = con.prepareStatement(insert);
+ ps.setQueryTimeout(0);
+ }
+
+ }
+ ps.close();
+ con.setAutoCommit(commit);
+ con.close();
+ }
+
+ public static Random random = new Random(System.currentTimeMillis());
+ public static String getRandom() {
+ StringBuilder s = new StringBuilder(256);
+ for (int i=0;i<254; i++) {
+ int b = Math.abs(random.nextInt() % 29);
+ char c = (char)(b+65);
+ s.append(c);
+ }
+ return s.toString();
+ }
+
+ public static void main(String[] args) throws Exception {
+ recreate = true;
+ CreateTestTable test = new CreateTestTable("CreateTestTable");
+ test.testPopulateData();
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+
+ //mysql
+ //url = System.getProperty("url","jdbc:mysql://localhost:3306/mysql?autoReconnect=true");
+ //driverClassName = System.getProperty("driverClassName","com.mysql.jdbc.Driver");
+
+ //derby
+ //url = System.getProperty("url","jdbc:derby:derbyDB;create=true");
+ //driverClassName = System.getProperty("driverClassName","org.apache.derby.jdbc.EmbeddedDriver");
+
+ url = System.getProperty("url","jdbc:h2:~/.h2/test;QUERY_TIMEOUT=0;DB_CLOSE_ON_EXIT=FALSE");
+ driverClassName = System.getProperty("driverClassName","org.h2.Driver");
+ System.setProperty("h2.serverCachedObjects", "10000");
+
+ password = System.getProperty("password","password");
+ username = System.getProperty("username","root");
+
+ validationQuery = System.getProperty("validationQuery","SELECT 1");
+ defaultAutoCommit = true;
+ defaultReadOnly = false;
+ defaultTransactionIsolation = DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION;
+ connectionProperties = null;
+ defaultCatalog = null;
+ initialSize = 10;
+ maxActive = 100;
+ maxIdle = initialSize;
+ minIdle = initialSize;
+ maxWait = 10000;
+
+ testOnBorrow = true;
+ testOnReturn = false;
+ testWhileIdle = true;
+ timeBetweenEvictionRunsMillis = 5000;
+ numTestsPerEvictionRun = 0;
+ minEvictableIdleTimeMillis = 1000;
+ removeAbandoned = true;
+ removeAbandonedTimeout = 5000;
+ logAbandoned = true;
+ validationInterval = 0; //always validate
+ initSQL = null;
+ testOnConnect = false;;
+ dbProperties.setProperty("user",username);
+ dbProperties.setProperty("password",password);
+ }
+}
--- /dev/null
+/*
+ * 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 junit.framework.TestCase;
+
+import org.apache.tomcat.dbcp.dbcp.BasicDataSource;
+import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+
+//import com.mchange.v2.c3p0.ComboPooledDataSource;
+//import com.mchange.v2.log.MLevel;
+//import com.mchange.v2.log.MLog;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class DefaultTestCase extends TestCase {
+ protected org.apache.tomcat.jdbc.pool.DataSource datasource;
+ protected BasicDataSource tDatasource;
+// protected ComboPooledDataSource c3p0Datasource;
+ protected int threadcount = 10;
+ protected int iterations = 100000;
+ public DefaultTestCase(String name) {
+ super(name);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ init();
+ }
+
+ public org.apache.tomcat.jdbc.pool.DataSource createDefaultDataSource() {
+ org.apache.tomcat.jdbc.pool.DataSource datasource = null;
+ PoolConfiguration p = new DefaultProperties();
+ p.setFairQueue(false);
+ 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(10);
+ p.setMinEvictableIdleTimeMillis(10000);
+ p.setMinIdle(threadcount);
+ p.setLogAbandoned(false);
+ p.setRemoveAbandoned(false);
+ datasource = new org.apache.tomcat.jdbc.pool.DataSource();
+ datasource.setPoolProperties(p);
+ return datasource;
+ }
+
+ protected void init() throws Exception {
+ this.datasource = createDefaultDataSource();
+ }
+
+ protected void transferProperties() {
+ try {
+ Properties p = new Properties();
+ for (int i=0; i< 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) BasicDataSourceFactory.createDataSource(p);
+ }catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+
+ protected void transferPropertiesToC3P0() throws Exception {
+// System.setProperty("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "WARNING");
+// MLog.getLogger().setLevel(MLevel.WARNING);
+// MLog.getLogger("com").setLevel(MLevel.WARNING);
+// //http://www.mchange.com/projects/c3p0/index.html#automaticTestTable
+// ComboPooledDataSource c3p0 = new ComboPooledDataSource();
+// c3p0.setAcquireIncrement(1);
+// c3p0.setAcquireRetryAttempts(2);
+// c3p0.setAcquireRetryDelay(datasource.getPoolProperties().getMaxWait());
+// c3p0.setCheckoutTimeout(datasource.getPoolProperties().getMaxWait());
+// c3p0.setDebugUnreturnedConnectionStackTraces(datasource.getPoolProperties().isLogAbandoned());
+// c3p0.setIdleConnectionTestPeriod(datasource.getPoolProperties().getTimeBetweenEvictionRunsMillis()/1000);
+// c3p0.setInitialPoolSize(datasource.getPoolProperties().getInitialSize());
+// c3p0.setMaxIdleTime(datasource.getPoolProperties().getMinEvictableIdleTimeMillis()/1000);
+// c3p0.setMaxIdleTimeExcessConnections(datasource.getPoolProperties().getMaxIdle());
+// c3p0.setMaxPoolSize(datasource.getPoolProperties().getMaxActive());
+// c3p0.setMinPoolSize(datasource.getPoolProperties().getMinIdle());
+// c3p0.setPassword(datasource.getPoolProperties().getPassword());
+// c3p0.setPreferredTestQuery(datasource.getPoolProperties().getValidationQuery());
+// c3p0.setTestConnectionOnCheckin(datasource.getPoolProperties().isTestOnReturn());
+// c3p0.setTestConnectionOnCheckout(datasource.getPoolProperties().isTestOnBorrow());
+// c3p0.setUnreturnedConnectionTimeout(datasource.getPoolProperties().getRemoveAbandonedTimeout());
+// c3p0.setUser(datasource.getPoolProperties().getUsername());
+// c3p0.setUsesTraditionalReflectiveProxies(true);
+// c3p0.setJdbcUrl(datasource.getPoolProperties().getUrl());
+// c3p0.setDriverClass(datasource.getPoolProperties().getDriverClassName());
+// this.c3p0Datasource = c3p0;
+
+ /**
+ acquireIncrement
+ acquireRetryAttempts
+ acquireRetryDelay
+ autoCommitOnClose
+ automaticTestTable
+ breakAfterAcquireFailure
+ checkoutTimeout
+ connectionCustomizerClassName
+ connectionTesterClassName
+ debugUnreturnedConnectionStackTraces
+ factoryClassLocation
+ forceIgnoreUnresolvedTransactions
+ idleConnectionTestPeriod
+ initialPoolSize
+ maxAdministrativeTaskTime
+ maxConnectionAge
+ maxIdleTime
+ maxIdleTimeExcessConnections
+ maxPoolSize
+ maxStatements
+ maxStatementsPerConnection
+ minPoolSize
+ numHelperThreads
+ overrideDefaultUser
+ overrideDefaultPassword
+ password
+ preferredTestQuery
+ propertyCycle
+ testConnectionOnCheckin
+ testConnectionOnCheckout
+ unreturnedConnectionTimeout
+ user
+ usesTraditionalReflectiveProxies
+ */
+ }
+
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {datasource.close();}catch(Exception ignore){}
+ try {tDatasource.close();}catch(Exception ignore){}
+ //try {((ComboPooledDataSource)c3p0Datasource).close(true);}catch(Exception ignore){}
+ datasource = null;
+ tDatasource = null;
+ //c3p0Datasource = null;
+ System.gc();
+ org.apache.tomcat.jdbc.test.driver.Driver.reset();
+ }
+
+ 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
+ };
+
+
+
+}
--- /dev/null
+/*
+ * 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.Future;
+import java.util.concurrent.TimeUnit;
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.ResultSet;
+
+import javax.sql.DataSource;
+
+import org.apache.tomcat.jdbc.pool.DataSourceProxy;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class FairnessTest extends DefaultTestCase {
+ public FairnessTest(String name) {
+ super(name);
+ }
+
+ protected boolean run = true;
+ protected long sleep = Long.getLong("sleep", 10);
+ protected long complete = Long.getLong("complete",20000);
+ protected boolean printthread = Boolean.getBoolean("printthread");
+ CountDownLatch latch = null;
+ protected void printThreadResults(TestThread[] threads, String name, int active, int expected) {
+ long minfetch = Long.MAX_VALUE, maxfetch = Long.MIN_VALUE, totalfetch = 0;
+ long maxwait = 0, minwait = Long.MAX_VALUE, averagewait = 0, totalwait = 0;
+ float avgfetch = 0;
+ for (int i=0; i<threads.length; i++) {
+ TestThread t = threads[i];
+ totalfetch += t.nroffetch;
+ totalwait += t.totalwait;
+ maxwait = Math.max(maxwait,t.maxwait);
+ minwait = Math.min(minwait, t.minwait);
+ minfetch = Math.min(minfetch, t.nroffetch);
+ maxfetch = Math.max(maxfetch, t.nroffetch);
+ if (FairnessTest.this.printthread)
+ System.out.println(t.getName()+" : Nr-of-fetch:"+t.nroffetch+ " Max fetch Time:"+(((float)t.maxwait)/1000000f)+"ms. :Max close time:"+(((float)t.cmax)/1000000f)+"ms.");
+ }
+ System.out.println("["+name+"] Max fetch:"+(maxfetch)+" Min fetch:"+(minfetch)+" Average fetch:"+
+ (((float)totalfetch))/(float)threads.length);
+ System.out.println("["+name+"] Max wait:"+(((float)maxwait)/1000000f)+"ms. Min wait:"+(((float)minwait)/1000000f)+"ms. Average wait:"+(((((float)totalwait))/(float)totalfetch)/1000000f)+" ms.");
+ System.out.println("["+name+"] Max active:"+active+" Expected Active:"+expected);
+
+
+ }
+
+ public void testDBCPThreads20Connections10() throws Exception {
+ System.out.println("[testDBCPThreads20Connections10] Starting fairness - DBCP");
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.threadcount = 20;
+ this.transferProperties();
+ this.tDatasource.getConnection().close();
+ latch = new CountDownLatch(threadcount);
+ long start = System.currentTimeMillis();
+ TestThread[] threads = new TestThread[threadcount];
+ for (int i=0; i<threadcount; i++) {
+ threads[i] = new TestThread();
+ threads[i].setName("tomcat-dbcp-"+i);
+ threads[i].d = this.tDatasource;
+
+ }
+ for (int i=0; i<threadcount; i++) {
+ threads[i].start();
+ }
+ if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+ System.out.println("Latch timed out.");
+ }
+ this.run = false;
+ long delta = System.currentTimeMillis() - start;
+ printThreadResults(threads,"testDBCPThreads20Connections10",this.tDatasource.getNumActive(),10);
+ tearDown();
+ }
+
+ public void testPoolThreads20Connections10() throws Exception {
+ System.out.println("[testPoolThreads20Connections10] Starting fairness - Tomcat JDBC - Non Fair");
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.datasource.getPoolProperties().setFairQueue(false);
+ this.threadcount = 20;
+ this.transferProperties();
+ this.datasource.getConnection().close();
+ latch = new CountDownLatch(threadcount);
+ long start = System.currentTimeMillis();
+ TestThread[] threads = new TestThread[threadcount];
+ for (int i=0; i<threadcount; i++) {
+ threads[i] = new TestThread();
+ threads[i].setName("tomcat-pool-"+i);
+ threads[i].d = this.datasource;
+
+ }
+ for (int i=0; i<threadcount; i++) {
+ threads[i].start();
+ }
+ if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+ System.out.println("Latch timed out.");
+ }
+ this.run = false;
+ long delta = System.currentTimeMillis() - start;
+ printThreadResults(threads,"testPoolThreads20Connections10",this.datasource.getSize(),10);
+ tearDown();
+
+ }
+
+ public void testPoolThreads20Connections10Fair() throws Exception {
+ System.out.println("[testPoolThreads20Connections10Fair] Starting fairness - Tomcat JDBC - Fair");
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.datasource.getPoolProperties().setFairQueue(true);
+ this.threadcount = 20;
+ this.transferProperties();
+ this.datasource.getConnection().close();
+ latch = new CountDownLatch(threadcount);
+ long start = System.currentTimeMillis();
+ TestThread[] threads = new TestThread[threadcount];
+ for (int i=0; i<threadcount; i++) {
+ threads[i] = new TestThread();
+ threads[i].setName("tomcat-pool-"+i);
+ threads[i].d = this.datasource;
+
+ }
+ for (int i=0; i<threadcount; i++) {
+ threads[i].start();
+ }
+ if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+ System.out.println("Latch timed out.");
+ }
+ this.run = false;
+ long delta = System.currentTimeMillis() - start;
+ printThreadResults(threads,"testPoolThreads20Connections10Fair",this.datasource.getSize(),10);
+ tearDown();
+ }
+
+ public void testPoolThreads20Connections10FairAsync() throws Exception {
+ System.out.println("[testPoolThreads20Connections10FairAsync] Starting fairness - Tomcat JDBC - Fair - Async");
+ init();
+ this.datasource.getPoolProperties().setMaxActive(10);
+ this.datasource.getPoolProperties().setFairQueue(true);
+ this.threadcount = 20;
+ this.transferProperties();
+ this.datasource.getConnection().close();
+ latch = new CountDownLatch(threadcount);
+ long start = System.currentTimeMillis();
+ TestThread[] threads = new TestThread[threadcount];
+ for (int i=0; i<threadcount; i++) {
+ threads[i] = new TestThread();
+ threads[i].setName("tomcat-pool-"+i);
+ threads[i].async = true;
+ threads[i].d = this.datasource;
+
+ }
+ for (int i=0; i<threadcount; i++) {
+ threads[i].start();
+ }
+ if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+ System.out.println("Latch timed out.");
+ }
+ this.run = false;
+ long delta = System.currentTimeMillis() - start;
+ printThreadResults(threads,"testPoolThreads20Connections10FairAsync",this.datasource.getSize(),10);
+ tearDown();
+ }
+
+// public void testC3P0Threads20Connections10() throws Exception {
+// System.out.println("[testC3P0Threads20Connections10] Starting fairness - C3P0");
+// init();
+// this.datasource.getPoolProperties().setMaxActive(10);
+// this.datasource.getPoolProperties().setFairQueue(false);
+// this.threadcount = 20;
+// this.transferPropertiesToC3P0();
+// this.datasource.getConnection().close();
+// latch = new CountDownLatch(threadcount);
+// long start = System.currentTimeMillis();
+// TestThread[] threads = new TestThread[threadcount];
+// for (int i=0; i<threadcount; i++) {
+// threads[i] = new TestThread();
+// threads[i].setName("tomcat-pool-"+i);
+// threads[i].d = this.c3p0Datasource;
+//
+// }
+// for (int i=0; i<threadcount; i++) {
+// threads[i].start();
+// }
+// if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
+// System.out.println("Latch timed out.");
+// }
+// this.run = false;
+// long delta = System.currentTimeMillis() - start;
+// printThreadResults(threads,"testC3P0Threads20Connections10",c3p0Datasource.getNumConnectionsAllUsers(),10);
+// tearDown();
+//
+// }
+
+
+ public class TestThread extends Thread {
+ protected DataSource d;
+ protected String query = null;
+ protected long sleep = 10;
+ protected boolean async = false;
+ long minwait = Long.MAX_VALUE, maxwait = -1, totalwait=0, totalcmax=0, cmax = -1, nroffetch = 0, totalruntime = 0;
+ @Override
+ public void run() {
+ try {
+ long now = System.currentTimeMillis();
+ while (FairnessTest.this.run) {
+ if ((System.currentTimeMillis()-now)>=FairnessTest.this.complete) break;
+ long start = System.nanoTime();
+ Connection con = null;
+ try {
+ if (async) {
+ Future<Connection> cf = ((DataSourceProxy)d).getConnectionAsync();
+ con = cf.get();
+ } else {
+ con = d.getConnection();
+ }
+ long delta = System.nanoTime() - start;
+ totalwait += delta;
+ maxwait = Math.max(delta, maxwait);
+ minwait = Math.min(delta, minwait);
+ nroffetch++;
+ if (query!=null) {
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery(query);
+ while (rs.next()) {
+ }
+ rs.close();
+ st.close();
+ }
+ try {
+ if (FairnessTest.this.sleep>0) sleep(FairnessTest.this.sleep);
+ } catch (InterruptedException x) {
+ interrupted();
+ }
+ } 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 {
+ FairnessTest.this.latch.countDown();
+ }
+ if (System.getProperty("print-thread-stats")!=null) {
+ System.out.println("["+getName()+"] "+
+ "\n\tMax time to retrieve connection:"+(((float)maxwait)/1000f/1000f)+" ms."+
+ "\n\tTotal time to retrieve connection:"+(((float)totalwait)/1000f/1000f)+" ms."+
+ "\n\tAverage time to retrieve connection:"+(((float)totalwait)/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);
+ }
+ }
+ }
+}
+
--- /dev/null
+/*
+ * 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.management.ManagementFactory;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PoolUtilities;
+import org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean;
+import org.apache.tomcat.jdbc.test.driver.Driver;
+
+public class JmxPasswordTest extends DefaultTestCase{
+ public static final String password = "password";
+ public static final String username = "username";
+ public static ObjectName oname = null;
+
+ public JmxPasswordTest(String s) {
+ super(s);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ this.datasource.setDriverClassName(Driver.class.getName());
+ this.datasource.setUrl("jdbc:tomcat:test");
+ this.datasource.setPassword(password);
+ this.datasource.setUsername(username);
+ this.datasource.getConnection().close();
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ String domain = "tomcat.jdbc";
+ Hashtable<String,String> properties = new Hashtable<String,String>();
+ properties.put("type", "ConnectionPool");
+ properties.put("class", this.getClass().getName());
+ oname = new ObjectName(domain,properties);
+ ConnectionPool pool = datasource.createPool();
+ org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool = new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(pool);
+ mbs.registerMBean(jmxPool, oname);
+
+ }
+
+ public void testPassword() throws Exception {
+ assertEquals("Passwords should match when not using JMX.",password,datasource.getPoolProperties().getPassword());
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ ConnectionPoolMBean mbean = JMX.newMBeanProxy(mbs, oname, ConnectionPoolMBean.class);
+ String jmxPassword = mbean.getPassword();
+ Properties jmxProperties = mbean.getDbProperties();
+ assertFalse("Passwords should not match.", password.equals(jmxPassword));
+ assertFalse("Password property should be missing", jmxProperties.containsKey(PoolUtilities.PROP_PASSWORD));
+ }
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.concurrent.Future;
+
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+
+public class SimplePOJOAsyncExample {
+
+ public static void main(String[] args) throws Exception {
+ PoolConfiguration p = new PoolProperties();
+ p.setFairQueue(true);
+ p.setUrl("jdbc:mysql://localhost:3306/mysql?autoReconnect=true");
+ p.setDriverClassName("com.mysql.jdbc.Driver");
+ p.setUsername("root");
+ p.setPassword("password");
+ p.setJmxEnabled(true);
+ p.setTestWhileIdle(false);
+ p.setTestOnBorrow(true);
+ p.setValidationQuery("SELECT 1");
+ p.setTestOnReturn(false);
+ p.setValidationInterval(30000);
+ p.setTimeBetweenEvictionRunsMillis(30000);
+ p.setMaxActive(100);
+ p.setInitialSize(10);
+ p.setMaxWait(10000);
+ p.setRemoveAbandonedTimeout(60);
+ p.setMinEvictableIdleTimeMillis(30000);
+ p.setMinIdle(10);
+ p.setLogAbandoned(true);
+ p.setRemoveAbandoned(true);
+ p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
+ DataSource datasource = new DataSource();
+ datasource.setPoolProperties(p);
+
+ Connection con = null;
+ try {
+ Future<Connection> future = datasource.getConnectionAsync();
+ while (!future.isDone()) {
+ System.out.println("Connection is not yet available. Do some background work");
+ try {
+ Thread.sleep(100); //simulate work
+ }catch (InterruptedException x) {
+ Thread.interrupted();
+ }
+ }
+ con = future.get(); //should return instantly
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery("select * from user");
+ int cnt = 1;
+ while (rs.next()) {
+ System.out.println((cnt++)+". Host:" +rs.getString("Host")+" User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
+ }
+ rs.close();
+ st.close();
+ } finally {
+ if (con!=null) try {con.close();}catch (Exception ignore) {}
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+
+public class SimplePOJOExample {
+
+ public static void main(String[] args) throws Exception {
+ PoolConfiguration p = new PoolProperties();
+ p.setUrl("jdbc:mysql://localhost:3306/mysql?autoReconnect=true");
+ p.setDriverClassName("com.mysql.jdbc.Driver");
+ p.setUsername("root");
+ p.setPassword("password");
+ p.setJmxEnabled(true);
+ p.setTestWhileIdle(false);
+ p.setTestOnBorrow(true);
+ p.setValidationQuery("SELECT 1");
+ p.setTestOnReturn(false);
+ p.setValidationInterval(30000);
+ p.setTimeBetweenEvictionRunsMillis(30000);
+ p.setMaxActive(100);
+ p.setInitialSize(10);
+ p.setMaxWait(10000);
+ p.setRemoveAbandonedTimeout(60);
+ p.setMinEvictableIdleTimeMillis(30000);
+ p.setMinIdle(10);
+ p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
+ p.setLogAbandoned(true);
+ p.setRemoveAbandoned(true);
+ DataSource datasource = new DataSource();
+ datasource.setPoolProperties(p);
+
+ Connection con = null;
+ try {
+ con = datasource.getConnection();
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery("select * from user");
+ int cnt = 1;
+ while (rs.next()) {
+ System.out.println((cnt++)+". Host:" +rs.getString("Host")+" User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
+ }
+ rs.close();
+ st.close();
+ } finally {
+ if (con!=null) try {con.close();}catch (Exception ignore) {}
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * If a connection is abandoned and closed,
+ * then that should free up a spot in the pool, and other threads
+ * that are waiting should not time out and throw an error but be
+ * able to acquire a connection, since one was just released.
+ * @author fhanik
+ *
+ */
+public class StarvationTest extends DefaultTestCase {
+
+ public StarvationTest(String name) {
+ super(name);
+ }
+
+ private void config() {
+ datasource.getPoolProperties().setMaxActive(1);
+ datasource.getPoolProperties().setMaxIdle(1);
+ datasource.getPoolProperties().setInitialSize(1);
+ datasource.getPoolProperties().setRemoveAbandoned(true);
+ datasource.getPoolProperties().setRemoveAbandonedTimeout(5);
+ datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(500);
+ datasource.getPoolProperties().setMaxWait(10000);
+ datasource.getPoolProperties().setLogAbandoned(true);
+ }
+
+// public void testDBCPConnectionStarvation() throws Exception {
+// init();
+// config();
+// this.transferProperties();
+// this.tDatasource.getConnection().close();
+// javax.sql.DataSource datasource = this.tDatasource;
+// Connection con1 = datasource.getConnection();
+// Connection con2 = null;
+// try {
+// con2 = datasource.getConnection();
+// try {
+// con2.setCatalog("mysql");//make sure connection is valid
+// }catch (SQLException x) {
+// assertFalse("2nd Connection is not valid:"+x.getMessage(),true);
+// }
+// assertTrue("Connection 1 should be closed.",con1.isClosed()); //first connection should be closed
+// }catch (Exception x) {
+// assertFalse("Connection got starved:"+x.getMessage(),true);
+// }finally {
+// if (con2!=null) con2.close();
+// }
+//
+// }
+
+ public void testConnectionStarvation() throws Exception {
+ init();
+ config();
+ Connection con1 = datasource.getConnection();
+ Connection con2 = null;
+ try {
+ con2 = datasource.getConnection();
+ try {
+ con2.setCatalog("mysql");//make sure connection is valid
+ }catch (SQLException x) {
+ assertFalse("2nd Connection is not valid:"+x.getMessage(),true);
+ }
+ assertTrue("Connection 1 should be closed.",con1.isClosed()); //first connection should be closed
+ }catch (Exception x) {
+ assertFalse("Connection got starved:"+x.getMessage(),true);
+ }finally {
+ if (con2!=null) con2.close();
+ }
+ }
+
+ public void testFairConnectionStarvation() throws Exception {
+ init();
+ config();
+ datasource.getPoolProperties().setFairQueue(true);
+ Connection con1 = datasource.getConnection();
+ Connection con2 = null;
+ try {
+ con2 = datasource.getConnection();
+ try {
+ con2.setCatalog("mysql");//make sure connection is valid
+ }catch (SQLException x) {
+ assertFalse("2nd Connection is not valid:"+x.getMessage(),true);
+ }
+ assertTrue("Connection 1 should be closed.",con1.isClosed()); //first connection should be closed
+ }catch (Exception x) {
+ assertFalse("Connection got starved:"+x.getMessage(),true);
+ }finally {
+ if (con2!=null) con2.close();
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.sql.Statement;
+
+import org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;
+
+public class StatementFinalizerTest extends DefaultTestCase {
+
+ public StatementFinalizerTest(String name) {
+ super(name);
+ }
+
+ public void testStatementFinalization() throws Exception {
+ this.init();
+ datasource.setJdbcInterceptors(StatementFinalizer.class.getName());
+ Connection con = datasource.getConnection();
+ Statement st = con.createStatement();
+ assertFalse("Statement should not be closed.",st.isClosed());
+ con.close();
+ assertTrue("Statement should be closed.",st.isClosed());
+ }
+
+}
--- /dev/null
+/*
+ * 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.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.tomcat.jdbc.pool.FairBlockingQueue;
+
+import junit.framework.TestCase;
+
+public class TestAsyncQueue extends TestCase {
+ protected FairBlockingQueue<Object> queue = null;
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.queue = new FairBlockingQueue<Object>();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ this.queue = null;
+ super.tearDown();
+ }
+
+
+ public void testAsyncPoll1() throws Exception {
+ Object item = new Object();
+ queue.offer(item);
+ Future<Object> future = queue.pollAsync();
+ assertEquals(future.get(),item);
+ }
+
+ public void testAsyncPoll2() throws Exception {
+ Object item = new Object();
+ OfferThread thread = new OfferThread(item,5000);
+ thread.start();
+ Future<Object> future = queue.pollAsync();
+ try {
+ future.get(2000, TimeUnit.MILLISECONDS);
+ assertFalse("Request should have timed out",true);
+ }catch (TimeoutException x) {
+ assertTrue("Request timed out properly",true);
+ }catch (Exception x) {
+ assertTrue("Request threw an error",false);
+ x.printStackTrace();
+ }
+ assertEquals(future.get(),item);
+ }
+
+ protected class OfferThread extends Thread {
+ Object item = null;
+ long delay = 5000;
+ volatile boolean offered = false;
+ public OfferThread(Object i, long d) {
+ this.item = i;
+ this.delay = d;
+ this.setDaemon(false);
+ this.setName(TestAsyncQueue.class.getName()+"-OfferThread");
+ }
+ @Override
+ public void run() {
+ try {
+ sleep(delay);
+ }catch (Exception ignore){}
+ offered = true;
+ TestAsyncQueue.this.queue.offer(item);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.apache.tomcat.jdbc.test.driver.Driver;
+
+public class TestConcurrency extends DefaultTestCase {
+
+ public static final boolean debug = Boolean.getBoolean("jdbc.debug");
+
+ protected volatile DataSource ds = null;
+
+ public TestConcurrency(String name) {
+ super(name);
+ }
+
+ @Override
+ public void setUp() {
+ // TODO Auto-generated method stub
+ ds = createDefaultDataSource();
+ ds.getPoolProperties().setDriverClassName(Driver.class.getName());
+ ds.getPoolProperties().setUrl(Driver.url);
+ ds.getPoolProperties().setInitialSize(0);
+ ds.getPoolProperties().setMaxIdle(0);
+ ds.getPoolProperties().setMinIdle(0);
+ ds.getPoolProperties().setMaxActive(10);
+ ds.getPoolProperties().setRemoveAbandoned(true);
+ ds.getPoolProperties().setLogAbandoned(true);
+ ds.getPoolProperties().setTestWhileIdle(true);
+ ds.getPoolProperties().setMinEvictableIdleTimeMillis(750);
+ ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(25);
+ ds.setFairQueue(true);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ ds.close(true);
+ Driver.reset();
+ super.tearDown();
+ }
+
+ public void testSimple() throws Exception {
+ ds.getConnection().close();
+ final int iter = 1000 * 10;
+ final AtomicInteger loopcount = new AtomicInteger(0);
+ final Runnable run = new Runnable() {
+ public void run() {
+ try {
+ while (loopcount.incrementAndGet() < iter) {
+ Connection con = ds.getConnection();
+ Thread.sleep(10);
+ con.close();
+ }
+ }catch (Exception x) {
+ loopcount.set(iter); //stops the test
+ x.printStackTrace();
+ }
+ }
+ };
+ Thread[] threads = new Thread[20];
+ for (int i=0; i<threads.length; i++) {
+ threads[i] = new Thread(run);
+ }
+ for (int i=0; i<threads.length; i++) {
+ threads[i].start();
+ }
+ try {
+ while (loopcount.get()<iter) {
+ assertTrue("Size comparison(less than 11):",ds.getPool().getSize()<=10);
+ if (debug) {
+ System.out.println("Size: "+ds.getPool().getSize());
+ System.out.println("Used: "+ds.getPool().getActive());
+ System.out.println("Idle: "+ds.getPool().getIdle());
+ System.out.println("Wait: "+ds.getPool().getWaitCount());
+ }
+ Thread.sleep(250);
+ }
+ }catch (Exception x) {
+ loopcount.set(iter); //stops the test
+ x.printStackTrace();
+ }
+ for (int i=0; i<threads.length; i++) {
+ threads[i].join();
+ }
+ assertEquals("Size comparison:",10, ds.getPool().getSize());
+ assertEquals("Idle comparison:",10, ds.getPool().getIdle());
+ assertEquals("Used comparison:",0, ds.getPool().getActive());
+ assertEquals("Connect count",10,Driver.connectCount.get());
+
+ }
+
+ public void testBrutal() throws Exception {
+ ds.getPoolProperties().setRemoveAbandoned(false);
+ ds.getPoolProperties().setRemoveAbandonedTimeout(1);
+ ds.getPoolProperties().setMinEvictableIdleTimeMillis(100);
+ ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(10);
+ ds.getConnection().close();
+ final int iter = 100000 * 10;
+ final AtomicInteger loopcount = new AtomicInteger(0);
+ final Runnable run = new Runnable() {
+ public void run() {
+ try {
+ while (loopcount.incrementAndGet() < iter) {
+ Connection con = ds.getConnection();
+ con.close();
+ }
+ }catch (Exception x) {
+ loopcount.set(iter); //stops the test
+ x.printStackTrace();
+ }
+ }
+ };
+ Thread[] threads = new Thread[20];
+ for (int i=0; i<threads.length; i++) {
+ threads[i] = new Thread(run);
+ }
+ for (int i=0; i<threads.length; i++) {
+ threads[i].start();
+ }
+ try {
+ while (loopcount.get()<iter) {
+ assertTrue("Size comparison(less than 11):",ds.getPool().getSize()<=10);
+ ds.getPool().testAllIdle();
+ ds.getPool().checkAbandoned();
+ ds.getPool().checkIdle();
+ }
+ }catch (Exception x) {
+ loopcount.set(iter); //stops the test
+ x.printStackTrace();
+ }
+ for (int i=0; i<threads.length; i++) {
+ threads[i].join();
+ }
+ System.out.println("Connect count:"+Driver.connectCount.get());
+ System.out.println("DisConnect count:"+Driver.disconnectCount.get());
+ assertEquals("Size comparison:",10, ds.getPool().getSize());
+ assertEquals("Idle comparison:",10, ds.getPool().getIdle());
+ assertEquals("Used comparison:",0, ds.getPool().getActive());
+ assertEquals("Connect count",10,Driver.connectCount.get());
+ }
+
+ public void testBrutalNonFair() throws Exception {
+ ds.getPoolProperties().setRemoveAbandoned(false);
+ ds.getPoolProperties().setRemoveAbandonedTimeout(1);
+ ds.getPoolProperties().setMinEvictableIdleTimeMillis(100);
+ ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(10);
+ ds.getConnection().close();
+ final int iter = 100000 * 10;
+ final AtomicInteger loopcount = new AtomicInteger(0);
+ final Runnable run = new Runnable() {
+ public void run() {
+ try {
+ while (loopcount.incrementAndGet() < iter) {
+ Connection con = ds.getConnection();
+ con.close();
+ }
+ }catch (Exception x) {
+ loopcount.set(iter); //stops the test
+ x.printStackTrace();
+ }
+ }
+ };
+ Thread[] threads = new Thread[20];
+ for (int i=0; i<threads.length; i++) {
+ threads[i] = new Thread(run);
+ }
+ for (int i=0; i<threads.length; i++) {
+ threads[i].start();
+ }
+ try {
+ while (loopcount.get()<iter) {
+ assertTrue("Size comparison(less than 11):",ds.getPool().getSize()<=10);
+ ds.getPool().testAllIdle();
+ ds.getPool().checkAbandoned();
+ ds.getPool().checkIdle();
+ }
+ }catch (Exception x) {
+ loopcount.set(iter); //stops the test
+ x.printStackTrace();
+ }
+ for (int i=0; i<threads.length; i++) {
+ threads[i].join();
+ }
+ System.out.println("Connect count:"+Driver.connectCount.get());
+ System.out.println("DisConnect count:"+Driver.disconnectCount.get());
+ assertEquals("Size comparison:",10, ds.getPool().getSize());
+ assertEquals("Idle comparison:",10, ds.getPool().getIdle());
+ assertEquals("Used comparison:",0, ds.getPool().getActive());
+ assertEquals("Connect count",10,Driver.connectCount.get());
+ }
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+
+import org.apache.tomcat.jdbc.pool.DataSourceProxy;
+import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
+
+public class TestConnectionState extends DefaultTestCase {
+
+ public TestConnectionState(String name) {
+ super(name);
+ }
+
+ public void testAutoCommitFalse() throws Exception {
+ DataSourceProxy d1 = this.createDefaultDataSource();
+ d1.setMaxActive(1);
+ d1.setMinIdle(1);
+ d1.setMaxIdle(1);
+ d1.setJdbcInterceptors(ConnectionState.class.getName());
+ d1.setDefaultAutoCommit(Boolean.FALSE);
+ Connection c1 = d1.getConnection();
+ assertFalse("Auto commit should be false",c1.getAutoCommit());
+ c1.setAutoCommit(true);
+ assertTrue("Auto commit should be true",c1.getAutoCommit());
+ c1.close();
+ c1 = d1.getConnection();
+ assertFalse("Auto commit should be false for a reused connection",c1.getAutoCommit());
+ d1.close(true);
+ assertTrue("Connection should be closed",c1.isClosed());
+ }
+
+ public void testAutoCommitTrue() throws Exception {
+ DataSourceProxy d1 = this.createDefaultDataSource();
+ d1.setMaxActive(1);
+ d1.setJdbcInterceptors(ConnectionState.class.getName());
+ d1.setDefaultAutoCommit(Boolean.TRUE);
+ d1.setMinIdle(1);
+ Connection c1 = d1.getConnection();
+ assertTrue("Auto commit should be true",c1.getAutoCommit());
+ c1.setAutoCommit(false);
+ assertFalse("Auto commit should be false",c1.getAutoCommit());
+ c1.close();
+ c1 = d1.getConnection();
+ assertTrue("Auto commit should be true for a reused connection",c1.getAutoCommit());
+ }
+
+ public void testDefaultCatalog() throws Exception {
+ DataSourceProxy d1 = this.createDefaultDataSource();
+ d1.setMaxActive(1);
+ d1.setJdbcInterceptors(ConnectionState.class.getName());
+ d1.setDefaultCatalog("information_schema");
+ d1.setMinIdle(1);
+ Connection c1 = d1.getConnection();
+ assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
+ c1.close();
+ c1 = d1.getConnection();
+ assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
+ c1.setCatalog("mysql");
+ assertEquals("Catalog should be information_schema",c1.getCatalog(),"mysql");
+ c1.close();
+ c1 = d1.getConnection();
+ assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
+ }
+
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+public class TestException extends DefaultTestCase {
+
+ public TestException(String name) {
+ super(name);
+ }
+
+ public void testException() throws Exception {
+ init();
+ datasource.getPoolProperties().setJdbcInterceptors(TestInterceptor.class.getName());
+ Connection con = datasource.getConnection();
+ try {
+ con.createStatement();
+ }catch (Exception x) {
+
+ }
+ }
+
+
+ public static class TestInterceptor extends JdbcInterceptor {
+
+ @Override
+ public void reset(ConnectionPool parent, PooledConnection con) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ }
+
+}
--- /dev/null
+/*
+ * 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(20000);
+ }
+
+ public void testClose() throws Exception {
+ init();
+ datasource.getConnection();
+ System.out.println("Got a connection, but didn't return it");
+ datasource.close(true);
+ Thread.sleep(20000);
+ }
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+
+import javax.sql.PooledConnection;
+
+public class TestGetConnection extends DefaultTestCase {
+
+ public TestGetConnection(String name) {
+ super(name);
+ }
+
+ public void testGetConnection() throws Exception {
+ this.init();
+ Connection con = this.datasource.getConnection();
+ assertTrue("Connection should implement javax.sql.PooledConnection",con instanceof PooledConnection);
+ Connection actual = ((PooledConnection)con).getConnection();
+ assertNotNull("Connection delegate should not be null.",actual);
+ System.out.println("Actual connection:"+actual.getClass().getName());
+
+ }
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+
+import org.apache.tomcat.jdbc.pool.interceptor.TestInterceptor;
+
+public class TestInterceptorShortName extends DefaultTestCase {
+
+ public TestInterceptorShortName(String name) {
+ super(name);
+ }
+
+ public void testShortInterceptor() throws Exception {
+ this.datasource = this.createDefaultDataSource();
+ this.datasource.setJdbcInterceptors("TestInterceptor");
+ this.datasource.setMaxActive(1);
+ Connection con = this.datasource.getConnection();
+ assertTrue("Pool should have been started.",TestInterceptor.poolstarted);
+ assertEquals("Only one interceptor should have been called setProperties",1,TestInterceptor.instancecount.get());
+ con.close();
+ this.datasource.close();
+ assertTrue("Pool should have been closed.",TestInterceptor.poolclosed);
+ }
+
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import junit.framework.TestCase;
+
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.apache.tomcat.jdbc.test.driver.Driver;
+/**
+ *
+ * @author Jeremy Norris
+ * https://issues.apache.org/bugzilla/show_bug.cgi?id=50613
+ *
+ */
+public class TestSizePreservation extends TestCase {
+
+ protected volatile DataSource ds = null;
+
+ public TestSizePreservation() {
+ }
+
+ private void initSimplePoolProperties() {
+ PoolConfiguration p = new DefaultProperties();
+ ds = new org.apache.tomcat.jdbc.pool.DataSource();
+ ds.setPoolProperties(p);
+
+ ds.getPoolProperties().setDriverClassName(Driver.class.getName());
+ ds.getPoolProperties().setUrl(Driver.url);
+ ds.getPoolProperties().setFairQueue(true);
+ ds.getPoolProperties().setJmxEnabled(false);
+ ds.getPoolProperties().setTestWhileIdle(true);
+ ds.getPoolProperties().setTestOnBorrow(false);
+ ds.getPoolProperties().setTestOnReturn(false);
+ ds.getPoolProperties().setValidationInterval(30000);
+ ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(30000);
+ ds.getPoolProperties().setInitialSize(100);
+ ds.getPoolProperties().setMaxActive(100);
+ ds.getPoolProperties().setMinIdle(0);
+ ds.getPoolProperties().setMaxIdle(0);
+ ds.getPoolProperties().setMaxWait(10000);
+ ds.getPoolProperties().setRemoveAbandonedTimeout(10);
+ ds.getPoolProperties().setMinEvictableIdleTimeMillis(10000);
+ ds.getPoolProperties().setLogAbandoned(false);
+ ds.getPoolProperties().setRemoveAbandoned(false);
+ ds.getPoolProperties().setUseLock(true);
+ }
+
+ private void initEvictingPool() {
+ initSimplePoolProperties();
+ ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(25);
+ ds.getPoolProperties().setMinEvictableIdleTimeMillis(750);
+ ds.getPoolProperties().setRemoveAbandoned(true);
+ ds.getPoolProperties().setRemoveAbandonedTimeout(1);
+ }
+
+ public void testSimple() throws Exception {
+ initSimplePoolProperties();
+ common();
+ ds.close(true);
+ Driver.reset();
+ }
+
+ public void testEvicting() throws Exception {
+ initEvictingPool();
+ common();
+ ds.close(true);
+ Driver.reset();
+ }
+
+ private void common() throws Exception {
+ ds.getConnection().close();
+ final int iterations = 1000;
+ final AtomicInteger loopcount = new AtomicInteger(0);
+ final Runnable run = new Runnable() {
+ public void run() {
+ try {
+ while (loopcount.incrementAndGet() < iterations) {
+ Connection c = ds.getConnection();
+ Thread.sleep(1000);
+ c.close();
+ }
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+ };
+ Thread[] threads = new Thread[200];
+ for (int i = 0; i < threads.length; i++) {
+ threads[i] = new Thread(run);
+ }
+ for (int i = 0; i < threads.length; i++) {
+ threads[i].start();
+ }
+ try {
+ while (loopcount.get() < iterations) {
+ Thread.sleep(250);
+ }
+ } catch (Exception x) {
+ loopcount.set(iterations); // stops the test
+ x.printStackTrace();
+ }
+ for (int i = 0; i < threads.length; i++) {
+ threads[i].join();
+ }
+ System.out.println("Pool size:"+ds.getPool().getSize());
+ assertTrue("Size validity check: ", ds.getPool().getSize() >= 0);
+ }
+
+}
--- /dev/null
+/*
+ * 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.management.ManagementFactory;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Map;
+
+import javax.management.AttributeChangeNotification;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport;
+import org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx;
+
+public class TestSlowQueryReport extends DefaultTestCase {
+
+ public TestSlowQueryReport(String name) {
+ super(name);
+ }
+
+ public void testSlowSql() throws Exception {
+ int count = 3;
+ this.init();
+ this.datasource.setMaxActive(1);
+ this.datasource.setJdbcInterceptors(SlowQueryReport.class.getName()+"(threshold=50)");
+ Connection con = this.datasource.getConnection();
+ String slowSql = "select count(1) from test where val1 like 'ewq%eq' and val2 = 'ew%rre' and val3 = 'sda%da' and val4 = 'dad%ada'";
+ for (int i=0; i<count; i++) {
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery(slowSql);
+ rs.close();
+ st.close();
+ }
+ Map<String,SlowQueryReport.QueryStats> map = SlowQueryReport.getPoolStats(datasource.getPool().getName());
+ assertNotNull(map);
+ assertEquals(1,map.size());
+ String key = map.keySet().iterator().next();
+ SlowQueryReport.QueryStats stats = map.get(key);
+ System.out.println("Stats:"+stats);
+
+ for (int i=0; i<count; i++) {
+ PreparedStatement st = con.prepareStatement(slowSql);
+ ResultSet rs = st.executeQuery();
+ rs.close();
+ st.close();
+ }
+ System.out.println("Stats:"+stats);
+
+ for (int i=0; i<count; i++) {
+ CallableStatement st = con.prepareCall(slowSql);
+ ResultSet rs = st.executeQuery();
+ rs.close();
+ st.close();
+ }
+ System.out.println("Stats:"+stats);
+ ConnectionPool pool = datasource.getPool();
+ con.close();
+ tearDown();
+ //make sure we actually did clean up when the pool closed
+ assertNull(SlowQueryReport.getPoolStats(pool.getName()));
+ }
+
+ public void testSlowSqlJmx() throws Exception {
+ int count = 1;
+ this.init();
+ this.datasource.setMaxActive(1);
+ this.datasource.setJdbcInterceptors(SlowQueryReportJmx.class.getName()+"(threshold=50,notifyPool=false)");
+ Connection con = this.datasource.getConnection();
+ String slowSql = "select count(1) from test where val1 like 'ewq%eq'";
+ for (int i=0; i<count; i++) {
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery(slowSql);
+ rs.close();
+ st.close();
+ }
+ Map<String,SlowQueryReport.QueryStats> map = SlowQueryReport.getPoolStats(datasource.getPool().getName());
+ assertNotNull(map);
+ assertEquals(1,map.size());
+ String key = map.keySet().iterator().next();
+ SlowQueryReport.QueryStats stats = map.get(key);
+ System.out.println("Stats:"+stats);
+ ClientListener listener = new ClientListener();
+ ConnectionPool pool = datasource.getPool();
+ ManagementFactory.getPlatformMBeanServer().addNotificationListener(
+ SlowQueryReportJmx.getObjectName(SlowQueryReportJmx.class, pool.getName()),
+ listener,
+ null,
+ null);
+
+ for (int i=0; i<count; i++) {
+ PreparedStatement st = con.prepareStatement(slowSql);
+ ResultSet rs = st.executeQuery();
+ rs.close();
+ st.close();
+ }
+ System.out.println("Stats:"+stats);
+
+ for (int i=0; i<count; i++) {
+ CallableStatement st = con.prepareCall(slowSql);
+ ResultSet rs = st.executeQuery();
+ rs.close();
+ st.close();
+ }
+ System.out.println("Stats:"+stats);
+ assertEquals("Expecting to have received "+(2*count)+" notifications.",2*count, listener.notificationCount);
+ con.close();
+ tearDown();
+ //make sure we actually did clean up when the pool closed
+ assertNull(SlowQueryReport.getPoolStats(pool.getName()));
+ }
+
+
+ public void testFastSql() throws Exception {
+ int count = 3;
+ this.init();
+ this.datasource.setMaxActive(1);
+ this.datasource.setJdbcInterceptors(SlowQueryReport.class.getName());
+ Connection con = this.datasource.getConnection();
+ String fastSql = this.datasource.getValidationQuery();
+ for (int i=0; i<count; i++) {
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery(fastSql);
+ rs.close();
+ st.close();
+ }
+ Map<String,SlowQueryReport.QueryStats> map = SlowQueryReport.getPoolStats(datasource.getPool().getName());
+ assertNotNull(map);
+ assertEquals(0,map.size());
+ ConnectionPool pool = datasource.getPool();
+ con.close();
+ tearDown();
+ assertNull(SlowQueryReport.getPoolStats(pool.getName()));
+ }
+
+ public void testFailedSql() throws Exception {
+ int count = 3;
+ this.init();
+ this.datasource.setMaxActive(1);
+ this.datasource.setJdbcInterceptors(SlowQueryReport.class.getName());
+ Connection con = this.datasource.getConnection();
+ String slowSql = "select 1 from non_existent";
+ int exceptionCount = 0;
+ for (int i=0; i<count; i++) {
+ Statement st = con.createStatement();
+ try {
+ ResultSet rs = st.executeQuery(slowSql);
+ rs.close();
+ }catch (Exception x) {
+ exceptionCount++;
+ }
+ st.close();
+
+ }
+ Map<String,SlowQueryReport.QueryStats> map = SlowQueryReport.getPoolStats(datasource.getPool().getName());
+ assertNotNull(map);
+ assertEquals(1,map.size());
+ ConnectionPool pool = datasource.getPool();
+ String key = map.keySet().iterator().next();
+ SlowQueryReport.QueryStats stats = map.get(key);
+ System.out.println("Stats:"+stats);
+ con.close();
+ tearDown();
+ assertNull(SlowQueryReport.getPoolStats(pool.getName()));
+ }
+
+
+ public class ClientListener implements NotificationListener {
+ volatile int notificationCount = 0;
+ public void handleNotification(Notification notification,
+ Object handback) {
+ notificationCount++;
+ System.out.println("\nReceived notification:");
+ System.out.println("\tClassName: " + notification.getClass().getName());
+ System.out.println("\tSource: " + notification.getSource());
+ System.out.println("\tType: " + notification.getType());
+ System.out.println("\tMessage: " + notification.getMessage());
+ if (notification instanceof AttributeChangeNotification) {
+ AttributeChangeNotification acn =
+ (AttributeChangeNotification) notification;
+ System.out.println("\tAttributeName: " + acn.getAttributeName());
+ System.out.println("\tAttributeType: " + acn.getAttributeType());
+ System.out.println("\tNewValue: " + acn.getNewValue());
+ System.out.println("\tOldValue: " + acn.getOldValue());
+ }
+ }
+ }
+
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+import java.sql.PreparedStatement;
+
+import org.apache.tomcat.jdbc.pool.interceptor.StatementCache;
+
+public class TestStatementCache extends DefaultTestCase {
+
+
+ public TestStatementCache(String name) {
+ super(name);
+ }
+
+ private static volatile TestStatementCacheInterceptor interceptor = null;
+
+
+ @Override
+ protected void tearDown() throws Exception {
+ // TODO Auto-generated method stub
+ this.interceptor = null;
+ super.tearDown();
+ }
+
+
+ private void config(boolean cachePrepared, boolean cacheCallable, int max) {
+ datasource.getPoolProperties().setJdbcInterceptors(TestStatementCacheInterceptor.class.getName()+
+ "(prepared="+cachePrepared+",callable="+cacheCallable+",max="+max+")");
+ }
+
+ public void testIsCacheEnabled() throws Exception {
+ init();
+ config(true,true,50);
+ datasource.getConnection().close();
+ assertNotNull("Interceptor was not created.", interceptor);
+ }
+
+ public void testCacheProperties() throws Exception {
+ init();
+ config(true,true,50);
+ datasource.getConnection().close();
+ assertEquals(true, interceptor.isCacheCallable());
+ assertEquals(true, interceptor.isCachePrepared());
+ assertEquals(50,interceptor.getMaxCacheSize());
+ }
+
+ public void testCacheProperties2() throws Exception {
+ init();
+ config(false,false,100);
+ datasource.getConnection().close();
+ assertEquals(false, interceptor.isCacheCallable());
+ assertEquals(false, interceptor.isCachePrepared());
+ assertEquals(100,interceptor.getMaxCacheSize());
+ }
+
+ public void testPreparedStatementCache() throws Exception {
+ init();
+ config(true,false,100);
+ Connection con = datasource.getConnection();
+ PreparedStatement ps1 = con.prepareStatement("select 1");
+ PreparedStatement ps2 = con.prepareStatement("select 1");
+ assertEquals(0,interceptor.getCacheSize().get());
+ ps1.close();
+ assertTrue(ps1.isClosed());
+ assertEquals(1,interceptor.getCacheSize().get());
+ PreparedStatement ps3 = con.prepareStatement("select 1");
+ assertEquals(0,interceptor.getCacheSize().get());
+ ps2.close();
+ assertTrue(ps2.isClosed());
+ ps3.close();
+ assertTrue(ps3.isClosed());
+ assertEquals(1,interceptor.getCacheSize().get());
+ }
+
+ public void testPreparedStatementCache2() throws Exception {
+ init();
+ config(false,false,100);
+ Connection con = datasource.getConnection();
+ PreparedStatement ps1 = con.prepareStatement("select 1");
+ PreparedStatement ps2 = con.prepareStatement("select 1");
+ assertEquals(0,interceptor.getCacheSize().get());
+ ps1.close();
+ assertTrue(ps1.isClosed());
+ assertEquals(0,interceptor.getCacheSize().get());
+ PreparedStatement ps3 = con.prepareStatement("select 1");
+ assertEquals(0,interceptor.getCacheSize().get());
+ ps2.close();
+ assertTrue(ps2.isClosed());
+ ps3.close();
+ assertTrue(ps3.isClosed());
+ assertEquals(0,interceptor.getCacheSize().get());
+ }
+
+ public void testCallableStatementCache() throws Exception {
+ }
+
+ public void testMaxCacheSize() throws Exception {
+ init();
+ config(true,false,100);
+ Connection con1 = datasource.getConnection();
+ Connection con2 = datasource.getConnection();
+ for (int i=0; i<120; i++) {
+ Connection con = (i%2==0)?con1:con2;
+ PreparedStatement ps = con.prepareStatement("select "+i);
+ ps.close();
+ }
+ assertEquals(100,interceptor.getCacheSize().get());
+ }
+
+
+ public static class TestStatementCacheInterceptor extends StatementCache {
+ public TestStatementCacheInterceptor() {
+ TestStatementCache.interceptor = this;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+
+public class TestSuspectTimeout extends DefaultTestCase {
+
+ public TestSuspectTimeout(String name) {
+ super(name);
+ }
+
+ public void testSuspect() throws Exception {
+ this.init();
+ this.datasource.setMaxActive(100);
+ this.datasource.setMaxIdle(100);
+ this.datasource.setInitialSize(0);
+ this.datasource.getPoolProperties().setAbandonWhenPercentageFull(0);
+ this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100);
+ this.datasource.getPoolProperties().setRemoveAbandoned(true);
+ this.datasource.getPoolProperties().setRemoveAbandonedTimeout(100);
+ this.datasource.getPoolProperties().setSuspectTimeout(1);
+ this.datasource.getPoolProperties().setLogAbandoned(true);
+ Connection con = datasource.getConnection();
+ assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
+ Thread.sleep(3000);
+ PooledConnection pcon = con.unwrap(PooledConnection.class);
+ assertTrue("Connection should be marked suspect",pcon.isSuspect());
+ con.close();
+ }
+}
--- /dev/null
+/*
+ * 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(5);
+ 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.");
+ }
+ assertTrue(false);
+ } catch ( Exception x ) {
+ assertTrue(true);
+ }finally {
+ Thread.sleep(2000);
+ tearDown();
+ }
+ }
+
+ public void testCheckoutTimeoutFair() throws Exception {
+ try {
+ init();
+ this.datasource.getPoolProperties().setFairQueue(true);
+ 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(5);
+ 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.");
+ }
+ assertTrue(false);
+ } catch ( Exception x ) {
+ assertTrue(true);
+ }finally {
+ Thread.sleep(2000);
+ tearDown();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.sql.Connection;
+
+public class TwoDataSources extends DefaultTestCase {
+
+ public TwoDataSources(String name) {
+ super(name);
+ }
+
+ public void testTwoDataSources() throws Exception {
+ org.apache.tomcat.jdbc.pool.DataSource d1 = this.createDefaultDataSource();
+ org.apache.tomcat.jdbc.pool.DataSource d2 = this.createDefaultDataSource();
+ d1.setRemoveAbandoned(true);
+ d1.setRemoveAbandonedTimeout(10);
+ d1.setTimeBetweenEvictionRunsMillis(1000);
+ d2.setRemoveAbandoned(false);
+ Connection c1 = d1.getConnection();
+ Connection c2 = d2.getConnection();
+ Thread.sleep(5000);
+ try {
+ c1.createStatement();
+ assertTrue("Connection should have been abandoned.",false);
+ }catch (Exception x) {
+ assertTrue("This is correct, c1 is abandoned",true);
+ }
+
+ try {
+ c2.createStatement();
+ assertTrue("Connection should not have been abandoned.",true);
+ }catch (Exception x) {
+ assertTrue("Connection c2 should be working",false);
+ }
+ try {
+ assertTrue("Connection should have been closed.",c1.isClosed());
+ }catch (Exception x) {
+ assertTrue("This is correct, c1 is closed",true);
+ }
+ try {
+ assertFalse("Connection c2 should not have been closed.",c2.isClosed());
+ }catch (Exception x) {
+ assertTrue("Connection c2 should be working",false);
+ }
+
+
+ }
+
+}
--- /dev/null
+/*
+ * 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.driver;
+
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+public class Connection implements java.sql.Connection {
+ Properties info;
+
+ public Connection(Properties info) {
+ this.info = info;
+ }
+
+ public String getUsername() {
+ return info.getProperty(PooledConnection.PROP_USER);
+ }
+
+ public String getPassword() {
+ return info.getProperty(PooledConnection.PROP_PASSWORD);
+ }
+
+ public void clearWarnings() throws SQLException {
+ }
+
+ public void close() throws SQLException {
+ Driver.disconnectCount.incrementAndGet();
+ }
+
+ public void commit() throws SQLException {
+ }
+
+ public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+ return null;
+ }
+
+ public Blob createBlob() throws SQLException {
+ return null;
+ }
+
+ public Clob createClob() throws SQLException {
+ return null;
+ }
+
+ public NClob createNClob() throws SQLException {
+ return null;
+ }
+
+ public SQLXML createSQLXML() throws SQLException {
+ return null;
+ }
+
+ public Statement createStatement() throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+ return null;
+ }
+
+ public boolean getAutoCommit() throws SQLException {
+ return false;
+ }
+
+ public String getCatalog() throws SQLException {
+ return null;
+ }
+
+ public Properties getClientInfo() throws SQLException {
+ return null;
+ }
+
+ public String getClientInfo(String name) throws SQLException {
+ return null;
+ }
+
+ public int getHoldability() throws SQLException {
+ return 0;
+ }
+
+ public DatabaseMetaData getMetaData() throws SQLException {
+ return null;
+ }
+
+ public int getTransactionIsolation() throws SQLException {
+ return 0;
+ }
+
+ public Map<String, Class<?>> getTypeMap() throws SQLException {
+ return null;
+ }
+
+ public SQLWarning getWarnings() throws SQLException {
+ return null;
+ }
+
+ public boolean isClosed() throws SQLException {
+ return false;
+ }
+
+ public boolean isReadOnly() throws SQLException {
+ return false;
+ }
+
+ public boolean isValid(int timeout) throws SQLException {
+ return false;
+ }
+
+ public String nativeSQL(String sql) throws SQLException {
+ return null;
+ }
+
+ public CallableStatement prepareCall(String sql) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public PreparedStatement prepareStatement(String sql) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+
+ public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return new org.apache.tomcat.jdbc.test.driver.Statement();
+ }
+
+ public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+ }
+
+ public void rollback() throws SQLException {
+ }
+
+ public void rollback(Savepoint savepoint) throws SQLException {
+ }
+
+ public void setAutoCommit(boolean autoCommit) throws SQLException {
+ }
+
+ public void setCatalog(String catalog) throws SQLException {
+ }
+
+ public void setClientInfo(Properties properties) throws SQLClientInfoException {
+ }
+
+ public void setClientInfo(String name, String value) throws SQLClientInfoException {
+ }
+
+ public void setHoldability(int holdability) throws SQLException {
+ }
+
+ public void setReadOnly(boolean readOnly) throws SQLException {
+ }
+
+ public Savepoint setSavepoint() throws SQLException {
+ return null;
+ }
+
+ public Savepoint setSavepoint(String name) throws SQLException {
+ return null;
+ }
+
+ public void setTransactionIsolation(int level) throws SQLException {
+ }
+
+ public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+ }
+
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return false;
+ }
+
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * 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.driver;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Driver implements java.sql.Driver {
+ public static final String url = "jdbc:tomcat:test";
+ public static final AtomicInteger connectCount = new AtomicInteger(0);
+ public static final AtomicInteger disconnectCount = new AtomicInteger(0);
+
+ public static void reset() {
+ connectCount.set(0);
+ disconnectCount.set(0);
+ }
+
+ static {
+ try {
+ DriverManager.registerDriver(new Driver());
+ }catch (Exception x) {
+ x.printStackTrace();
+ throw new RuntimeException(x);
+ }
+ }
+
+ public Driver() {
+ }
+
+ public boolean acceptsURL(String url) throws SQLException {
+ return url!=null && url.equals(Driver.url);
+ }
+
+ public Connection connect(String url, Properties info) throws SQLException {
+ connectCount.addAndGet(1);
+ return new org.apache.tomcat.jdbc.test.driver.Connection(info);
+ }
+
+ public int getMajorVersion() {
+ return 0;
+ }
+
+ public int getMinorVersion() {
+ return 0;
+ }
+
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
+ return null;
+ }
+
+ public boolean jdbcCompliant() {
+ return false;
+ }
+}
--- /dev/null
+/*
+ * 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.driver;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSet implements java.sql.ResultSet {
+ boolean hasNext = true;
+
+ public boolean absolute(int row) throws SQLException {
+ return false;
+ }
+
+ public void afterLast() throws SQLException {
+ }
+
+ public void beforeFirst() throws SQLException {
+ }
+
+ public void cancelRowUpdates() throws SQLException {
+ }
+
+ public void clearWarnings() throws SQLException {
+ }
+ public void close() throws SQLException {
+ }
+
+ public void deleteRow() throws SQLException {
+ }
+
+ public int findColumn(String columnLabel) throws SQLException {
+ return 0;
+ }
+
+ public boolean first() throws SQLException {
+ return hasNext;
+ }
+
+ public Array getArray(int columnIndex) throws SQLException {
+ return null;
+ }
+
+ public Array getArray(String columnLabel) throws SQLException {
+ return null;
+ }
+
+ @Override
+ public InputStream getAsciiStream(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public InputStream getAsciiStream(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(int columnIndex, int scale)
+ throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(String columnLabel, int scale)
+ throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public InputStream getBinaryStream(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public InputStream getBinaryStream(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Blob getBlob(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Blob getBlob(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean getBoolean(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean getBoolean(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public byte getByte(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public byte getByte(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public byte[] getBytes(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public byte[] getBytes(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Reader getCharacterStream(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Reader getCharacterStream(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Clob getClob(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Clob getClob(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getConcurrency() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String getCursorName() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDate(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDate(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDate(int columnIndex, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDate(String columnLabel, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public double getDouble(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public double getDouble(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getFetchDirection() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getFetchSize() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getFloat(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getFloat(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getHoldability() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getInt(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getInt(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public long getLong(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public long getLong(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public ResultSetMetaData getMetaData() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Reader getNCharacterStream(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Reader getNCharacterStream(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NClob getNClob(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NClob getNClob(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getNString(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getNString(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getObject(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getObject(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getObject(int columnIndex, Map<String, Class<?>> map)
+ throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getObject(String columnLabel, Map<String, Class<?>> map)
+ throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Ref getRef(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Ref getRef(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getRow() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public RowId getRowId(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public RowId getRowId(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SQLXML getSQLXML(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SQLXML getSQLXML(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public short getShort(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public short getShort(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public Statement getStatement() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getString(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getString(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Time getTime(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Time getTime(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Time getTime(int columnIndex, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Time getTime(String columnLabel, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Timestamp getTimestamp(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Timestamp getTimestamp(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Timestamp getTimestamp(int columnIndex, Calendar cal)
+ throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Timestamp getTimestamp(String columnLabel, Calendar cal)
+ throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getType() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public URL getURL(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public URL getURL(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public InputStream getUnicodeStream(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public InputStream getUnicodeStream(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SQLWarning getWarnings() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void insertRow() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean isAfterLast() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isBeforeFirst() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isFirst() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isLast() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean last() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void moveToCurrentRow() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void moveToInsertRow() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean next() throws SQLException {
+ boolean next = hasNext;
+ hasNext = false;
+ // TODO Auto-generated method stub
+ return next;
+ }
+
+ @Override
+ public boolean previous() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void refreshRow() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean relative(int rows) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean rowDeleted() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean rowInserted() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean rowUpdated() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void setFetchDirection(int direction) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setFetchSize(int rows) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateArray(int columnIndex, Array x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateArray(String columnLabel, Array x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateAsciiStream(int columnIndex, InputStream x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateAsciiStream(String columnLabel, InputStream x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateAsciiStream(int columnIndex, InputStream x, int length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateAsciiStream(String columnLabel, InputStream x, int length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateAsciiStream(int columnIndex, InputStream x, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateAsciiStream(String columnLabel, InputStream x, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBigDecimal(int columnIndex, BigDecimal x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBigDecimal(String columnLabel, BigDecimal x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBinaryStream(int columnIndex, InputStream x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBinaryStream(String columnLabel, InputStream x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBinaryStream(int columnIndex, InputStream x, int length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBinaryStream(String columnLabel, InputStream x, int length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBinaryStream(int columnIndex, InputStream x, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBinaryStream(String columnLabel, InputStream x,
+ long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBlob(int columnIndex, Blob x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBlob(String columnLabel, Blob x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBlob(int columnIndex, InputStream inputStream)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBlob(String columnLabel, InputStream inputStream)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBlob(int columnIndex, InputStream inputStream, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBlob(String columnLabel, InputStream inputStream,
+ long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBoolean(int columnIndex, boolean x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBoolean(String columnLabel, boolean x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateByte(int columnIndex, byte x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateByte(String columnLabel, byte x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBytes(int columnIndex, byte[] x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateBytes(String columnLabel, byte[] x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateCharacterStream(int columnIndex, Reader x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateCharacterStream(String columnLabel, Reader reader)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateCharacterStream(int columnIndex, Reader x, int length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateCharacterStream(String columnLabel, Reader reader,
+ int length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateCharacterStream(int columnIndex, Reader x, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateCharacterStream(String columnLabel, Reader reader,
+ long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateClob(int columnIndex, Clob x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateClob(String columnLabel, Clob x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateClob(int columnIndex, Reader reader) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateClob(String columnLabel, Reader reader)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateClob(int columnIndex, Reader reader, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateClob(String columnLabel, Reader reader, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateDate(int columnIndex, Date x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateDate(String columnLabel, Date x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateDouble(int columnIndex, double x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateDouble(String columnLabel, double x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateFloat(int columnIndex, float x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateFloat(String columnLabel, float x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateInt(int columnIndex, int x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateInt(String columnLabel, int x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateLong(int columnIndex, long x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateLong(String columnLabel, long x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNCharacterStream(int columnIndex, Reader x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNCharacterStream(String columnLabel, Reader reader)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNCharacterStream(int columnIndex, Reader x, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNCharacterStream(String columnLabel, Reader reader,
+ long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, NClob clob) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, NClob clob) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, Reader reader) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, Reader reader)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, Reader reader, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, Reader reader, long length)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNString(int columnIndex, String string)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNString(String columnLabel, String string)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNull(int columnIndex) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNull(String columnLabel) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateObject(int columnIndex, Object x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateObject(String columnLabel, Object x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateObject(int columnIndex, Object x, int scaleOrLength)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateObject(String columnLabel, Object x, int scaleOrLength)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateRef(int columnIndex, Ref x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateRef(String columnLabel, Ref x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateRow() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateRowId(int columnIndex, RowId x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateRowId(String columnLabel, RowId x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateSQLXML(int columnIndex, SQLXML xmlObject)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateSQLXML(String columnLabel, SQLXML xmlObject)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateShort(int columnIndex, short x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateShort(String columnLabel, short x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateString(int columnIndex, String x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateString(String columnLabel, String x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateTime(int columnIndex, Time x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateTime(String columnLabel, Time x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateTimestamp(int columnIndex, Timestamp x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateTimestamp(String columnLabel, Timestamp x)
+ throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean wasNull() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * 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.driver;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.ParameterMetaData;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Map;
+
+public class Statement implements CallableStatement {
+
+ @Override
+ public Array getArray(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Array getArray(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Blob getBlob(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Blob getBlob(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean getBoolean(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean getBoolean(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public byte getByte(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public byte getByte(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public byte[] getBytes(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public byte[] getBytes(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Reader getCharacterStream(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Reader getCharacterStream(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Clob getClob(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Clob getClob(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDate(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDate(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDate(int parameterIndex, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDate(String parameterName, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public double getDouble(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public double getDouble(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getFloat(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getFloat(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getInt(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getInt(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public long getLong(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public long getLong(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public Reader getNCharacterStream(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Reader getNCharacterStream(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NClob getNClob(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NClob getNClob(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getNString(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getNString(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getObject(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getObject(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getObject(int parameterIndex, Map<String, Class<?>> map) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getObject(String parameterName, Map<String, Class<?>> map) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Ref getRef(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Ref getRef(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public RowId getRowId(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public RowId getRowId(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SQLXML getSQLXML(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SQLXML getSQLXML(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public short getShort(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public short getShort(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String getString(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getString(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Time getTime(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Time getTime(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Time getTime(int parameterIndex, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Time getTime(String parameterName, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Timestamp getTimestamp(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Timestamp getTimestamp(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Timestamp getTimestamp(int parameterIndex, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Timestamp getTimestamp(String parameterName, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public URL getURL(int parameterIndex) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public URL getURL(String parameterName) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void registerOutParameter(String parameterName, int sqlType) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void registerOutParameter(int parameterIndex, int sqlType, int scale) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void registerOutParameter(String parameterName, int sqlType, int scale) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void registerOutParameter(String parameterName, int sqlType, String typeName) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setAsciiStream(String parameterName, InputStream x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setAsciiStream(String parameterName, InputStream x, int length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setAsciiStream(String parameterName, InputStream x, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBigDecimal(String parameterName, BigDecimal x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBinaryStream(String parameterName, InputStream x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBinaryStream(String parameterName, InputStream x, int length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBinaryStream(String parameterName, InputStream x, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBlob(String parameterName, Blob x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBlob(String parameterName, InputStream inputStream) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBoolean(String parameterName, boolean x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setByte(String parameterName, byte x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBytes(String parameterName, byte[] x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setCharacterStream(String parameterName, Reader reader) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setCharacterStream(String parameterName, Reader reader, int length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setClob(String parameterName, Clob x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setClob(String parameterName, Reader reader) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setClob(String parameterName, Reader reader, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setDate(String parameterName, Date x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setDate(String parameterName, Date x, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setDouble(String parameterName, double x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setFloat(String parameterName, float x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setInt(String parameterName, int x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setLong(String parameterName, long x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNCharacterStream(String parameterName, Reader value) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNClob(String parameterName, NClob value) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNClob(String parameterName, Reader reader) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNClob(String parameterName, Reader reader, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNString(String parameterName, String value) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNull(String parameterName, int sqlType) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNull(String parameterName, int sqlType, String typeName) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setObject(String parameterName, Object x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setObject(String parameterName, Object x, int targetSqlType) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setObject(String parameterName, Object x, int targetSqlType, int scale) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setRowId(String parameterName, RowId x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setShort(String parameterName, short x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setString(String parameterName, String x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTime(String parameterName, Time x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTime(String parameterName, Time x, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTimestamp(String parameterName, Timestamp x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTimestamp(String parameterName, Timestamp x, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setURL(String parameterName, URL val) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean wasNull() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void addBatch() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void clearParameters() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean execute() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public ResultSet executeQuery() throws SQLException {
+ // TODO Auto-generated method stub
+ return new org.apache.tomcat.jdbc.test.driver.ResultSet();
+ }
+
+ @Override
+ public int executeUpdate() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public ResultSetMetaData getMetaData() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ParameterMetaData getParameterMetaData() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setArray(int parameterIndex, Array x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBlob(int parameterIndex, Blob x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBoolean(int parameterIndex, boolean x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setByte(int parameterIndex, byte x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setBytes(int parameterIndex, byte[] x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setClob(int parameterIndex, Clob x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setClob(int parameterIndex, Reader reader) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setDate(int parameterIndex, Date x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setDouble(int parameterIndex, double x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setFloat(int parameterIndex, float x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setInt(int parameterIndex, int x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setLong(int parameterIndex, long x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNClob(int parameterIndex, NClob value) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNClob(int parameterIndex, Reader reader) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNString(int parameterIndex, String value) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNull(int parameterIndex, int sqlType) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setObject(int parameterIndex, Object x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setRef(int parameterIndex, Ref x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setRowId(int parameterIndex, RowId x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setShort(int parameterIndex, short x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setString(int parameterIndex, String x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTime(int parameterIndex, Time x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setURL(int parameterIndex, URL x) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void addBatch(String sql) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void cancel() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void clearBatch() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void clearWarnings() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void close() throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean execute(String sql) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean execute(String sql, int[] columnIndexes) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean execute(String sql, String[] columnNames) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public int[] executeBatch() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ResultSet executeQuery(String sql) throws SQLException {
+ // TODO Auto-generated method stub
+ return new org.apache.tomcat.jdbc.test.driver.ResultSet();
+ }
+
+ @Override
+ public int executeUpdate(String sql) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int executeUpdate(String sql, String[] columnNames) throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getFetchDirection() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getFetchSize() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public ResultSet getGeneratedKeys() throws SQLException {
+ // TODO Auto-generated method stub
+ return new org.apache.tomcat.jdbc.test.driver.ResultSet();
+ }
+
+ @Override
+ public int getMaxFieldSize() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getMaxRows() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public boolean getMoreResults() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean getMoreResults(int current) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public int getQueryTimeout() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public ResultSet getResultSet() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getResultSetConcurrency() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getResultSetHoldability() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getResultSetType() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getUpdateCount() throws SQLException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public SQLWarning getWarnings() throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isPoolable() throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void setCursorName(String name) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setEscapeProcessing(boolean enable) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setFetchDirection(int direction) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setFetchSize(int rows) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setMaxFieldSize(int max) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setMaxRows(int max) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setPoolable(boolean poolable) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setQueryTimeout(int seconds) throws SQLException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
+++ /dev/null
-/*
- * 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.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
-
-public class TestInterceptor extends JdbcInterceptor {
- public static boolean poolstarted = false;
- public static boolean poolclosed = false;
- public static AtomicInteger instancecount = new AtomicInteger(0);
-
- @Override
- public void poolClosed(ConnectionPool pool) {
- // TODO Auto-generated method stub
- super.poolClosed(pool);
- poolclosed = true;
- }
-
- @Override
- public void poolStarted(ConnectionPool pool) {
- super.poolStarted(pool);
- poolstarted = true;
- }
-
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setProperties(Map<String, InterceptorProperty> properties) {
- instancecount.incrementAndGet();
- super.setProperties(properties);
- }
-
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer;
-
-public class AbandonPercentageTest extends DefaultTestCase {
-
- public AbandonPercentageTest(String name) {
- super(name);
- }
-
- public void testDefaultAbandon() throws Exception {
- this.init();
- this.datasource.setMaxActive(100);
- this.datasource.setMaxIdle(100);
- this.datasource.setInitialSize(0);
- this.datasource.getPoolProperties().setAbandonWhenPercentageFull(0);
- this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100);
- this.datasource.getPoolProperties().setRemoveAbandoned(true);
- this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
- Connection con = datasource.getConnection();
- assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
- Thread.sleep(2000);
- assertEquals("Number of connections active/busy should be 0",0,datasource.getPool().getActive());
- con.close();
- }
-
- public void testMaxedOutAbandon() throws Exception {
- int size = 100;
- this.init();
- this.datasource.setMaxActive(size);
- this.datasource.setMaxIdle(size);
- this.datasource.setInitialSize(0);
- this.datasource.getPoolProperties().setAbandonWhenPercentageFull(100);
- this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100);
- this.datasource.getPoolProperties().setRemoveAbandoned(true);
- this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
- Connection con = datasource.getConnection();
- assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
- Thread.sleep(2000);
- assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
- con.close();
- }
-
- public void testResetConnection() throws Exception {
- int size = 1;
- this.init();
- this.datasource.setMaxActive(size);
- this.datasource.setMaxIdle(size);
- this.datasource.setInitialSize(0);
- this.datasource.getPoolProperties().setAbandonWhenPercentageFull(100);
- this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100);
- this.datasource.getPoolProperties().setRemoveAbandoned(true);
- this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
- this.datasource.getPoolProperties().setJdbcInterceptors(ResetAbandonedTimer.class.getName());
- Connection con = datasource.getConnection();
- assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
- for (int i=0; i<20; i++) {
- Thread.sleep(200);
- con.isClosed();
- }
- assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
- con.close();
- }
-
- public void testHalfway() throws Exception {
- int size = 100;
- this.init();
- this.datasource.setMaxActive(size);
- this.datasource.setMaxIdle(size);
- this.datasource.setInitialSize(0);
- this.datasource.getPoolProperties().setAbandonWhenPercentageFull(50);
- this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(500);
- this.datasource.getPoolProperties().setRemoveAbandoned(true);
- this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
- Connection[] con = new Connection[size];
- con[0] = datasource.getConnection();
- assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
- for (int i=1; i<25; i++) {
- con[i] = datasource.getConnection();
- }
- assertEquals("Number of connections active/busy should be 25",25,datasource.getPool().getActive());
- Thread.sleep(2500);
- assertEquals("Number of connections active/busy should be 25",25,datasource.getPool().getActive());
- this.datasource.getPoolProperties().setRemoveAbandonedTimeout(100);
- for (int i=25; i<con.length; i++) {
- con[i] = datasource.getConnection();
- }
- int active = datasource.getPool().getActive();
- System.out.println("Active:"+active);
- assertEquals("Number of connections active/busy should be "+con.length,con.length,datasource.getPool().getActive());
- this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
- Thread.sleep(2500);
- this.assertTrue("Number of connections should be less than 50.", (datasource.getPool().getActive()<50));
- this.datasource.getPoolProperties().setAbandonWhenPercentageFull(0);
- Thread.sleep(2500);
- assertEquals("Number of connections active/busy should be "+0,0,datasource.getPool().getActive());
- }
-}
+++ /dev/null
-/*
- * 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.sql.SQLException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import javax.sql.PooledConnection;
-
-import org.apache.tomcat.jdbc.test.driver.Connection;
-import org.apache.tomcat.jdbc.test.driver.Driver;
-
-
-public class AlternateUsernameTest extends DefaultTestCase {
-
- private static final int iterations = 500000; //(new Random(System.currentTimeMillis())).nextInt(1000000)+100000;
- public AlternateUsernameTest(String name) {
- super(name);
- }
- public void testUsernameCompare() throws Exception {
- testUsername(true);
- }
-
- private void testUsername(boolean allowUsernameChange) throws Exception {
- long start = System.currentTimeMillis();
- int withoutuser =10;
- int withuser = withoutuser;
- this.init();
- this.datasource.setMaxActive(withuser+withoutuser);
- this.datasource.setDriverClassName(Driver.class.getName());
- this.datasource.setUrl("jdbc:tomcat:test");
- this.datasource.setAlternateUsernameAllowed(allowUsernameChange);
- this.datasource.getConnection().close();
-
- TestRunner[] runners = new TestRunner[withuser+withoutuser];
- for (int i=0; i<withuser; i++) {
- TestRunner with = new TestRunner("foo","bar",datasource.getPoolProperties().getUsername(),datasource.getPoolProperties().getPassword());
- TestRunner without = new TestRunner(null,null,datasource.getPoolProperties().getUsername(),datasource.getPoolProperties().getPassword());
- runners[i] = allowUsernameChange?with:without;
- runners[i+withuser] = without;
- }
- ExecutorService svc = Executors.newFixedThreadPool(withuser+withoutuser);
- List<Future<TestResult>> results = svc.invokeAll(Arrays.asList(runners));
- int failures = 0;
- int total = 0;
- for (int i=0; i<withuser; i++) {
- failures += results.get(i).get().failures;
- total+=results.get(i).get().iterations;
- failures += results.get(i+withuser).get().failures;
- total+=results.get(i+withuser).get().iterations;
- }
- long stop = System.currentTimeMillis();
- assertEquals("Nr of failures was:"+failures,0, failures);
- svc.shutdownNow();
- this.datasource.close();
- System.out.println("Nr of connect() calls:"+Driver.connectCount.get());
- System.out.println("Nr of disconnect() calls:"+Driver.disconnectCount.get());
- System.out.println("Nr of iterations:"+total+" over "+(stop-start)+ " ms.");
-
- }
-
- public void testUsernameCompareAgain() throws Exception {
- testUsernameCompare();
- }
-
- public void testUsernameCompareNotAllowed() throws Exception {
- testUsername(false);
- }
-
- public static class TestResult {
- public int iterations;
- public int failures;
- public String lastMessage;
- }
-
- public class TestRunner implements Callable<TestResult> {
- String username;
- String password;
- volatile boolean done = false;
- TestResult result = null;
- boolean useuser = true;
-
- public TestRunner(String user, String pass, String guser, String gpass) {
- username = user==null?guser : user;
- password = pass==null?gpass : pass;
- useuser = user!=null;
- }
-
- public TestResult call() {
- TestResult test = new TestResult();
- PooledConnection pcon = null;
- for (int i=0; (!done) && (i<iterations); i++) {
- test.iterations = i+1;
- try {
-
-
- pcon = useuser ? (PooledConnection)AlternateUsernameTest.this.datasource.getConnection(username, password) :
- (PooledConnection)AlternateUsernameTest.this.datasource.getConnection();
-
- Connection con = (Connection)pcon.getConnection();
-
- assertTrue("Username mismatch: Requested User:"+username+" Actual user:"+con.getUsername(), con.getUsername().equals(username));
- assertTrue("Password mismatch: Requested Password:"+password+" Actual password:"+con.getPassword(), con.getPassword().equals(password));
- }catch (SQLException x) {
- test.failures++;
- test.lastMessage = x.getMessage();
- done = true;
- x.printStackTrace();
- }catch (Exception x) {
- test.failures++;
- test.lastMessage = x.getMessage();
- x.printStackTrace();
- } finally {
- if (pcon!=null) {
- try {pcon.close(); }catch (Exception ignore) {}
- pcon = null;
- }
- }
- }
- done = true;
- result = test;
- return result;
- }
- }
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.tomcat.jdbc.pool.DataSourceProxy;
-
-/**
- * @author Filip Hanik
- * @version 1.0
- */
-public class Async0IdleTestBug50477 extends DefaultTestCase {
- public Async0IdleTestBug50477(String name) {
- super(name);
- }
-
-
- public void testAsync0Idle0Size() throws Exception {
- System.out.println("[testPoolThreads20Connections10FairAsync] Starting fairness - Tomcat JDBC - Fair - Async");
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.datasource.getPoolProperties().setFairQueue(true);
- this.datasource.getPoolProperties().setInitialSize(0);
- try {
- Future<Connection> cf = ((DataSourceProxy)datasource).getConnectionAsync();
- Connection con = cf.get(5, TimeUnit.SECONDS);
- }finally {
- tearDown();
- }
- }
-}
-
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.sql.SQLException;
-
-public class BorrowWaitTest extends DefaultTestCase {
-
- public BorrowWaitTest(String name) {
- super(name);
- }
-
- public void testWaitTime() throws Exception {
- int wait = 10000;
- this.init();
- this.datasource.setMaxActive(1);
- this.datasource.setMaxWait(wait);
- Connection con = datasource.getConnection();
- try {
- Connection con2 = datasource.getConnection();
- assertFalse("This should not happen, connection should be unavailable.",true);
- con2.close();
- }catch (SQLException x) {
- long delta = System.currentTimeMillis();
- boolean inrange = Math.abs(wait-delta) < 1000;
- assertTrue("Connection should have been acquired within +/- 1 second.",true);
- }
- con.close();
- }
-
- public void testWaitTimeInfinite() throws Exception {
- if(true){
- System.err.println("testWaitTimeInfinite() test is disabled.");
- return;//this would lock up the test suite
- }
- int wait = -1;
- this.init();
- this.datasource.setMaxActive(1);
- this.datasource.setMaxWait(wait);
- Connection con = datasource.getConnection();
- long start = System.currentTimeMillis();
- try {
- Connection con2 = datasource.getConnection();
- assertFalse("This should not happen, connection should be unavailable.",true);
- }catch (SQLException x) {
- long delta = System.currentTimeMillis();
- boolean inrange = Math.abs(wait-delta) < 1000;
- assertTrue("Connection should have been acquired within +/- 1 second.",true);
- }
- con.close();
- }
-
-
-}
+++ /dev/null
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.jdbc.test;\r
-\r
-import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;\r
-\r
-public class Bug50571 extends DefaultTestCase{\r
- \r
- public Bug50571(String name) {\r
- super(name);\r
- }\r
- \r
- @Override\r
- public void setUp() throws Exception {\r
- super.setUp();\r
- this.datasource.setUrl("jdbc:h2:~/.h2/test;QUERY_TIMEOUT=0;DB_CLOSE_ON_EXIT=FALSE");\r
- this.datasource.setJdbcInterceptors(ConnectionState.class.getName());\r
- this.datasource.setDefaultTransactionIsolation(-55);\r
- this.datasource.setInitialSize(1);\r
- }\r
- \r
- public void testBug50571() throws Exception {\r
- this.datasource.getConnection().close();\r
- }\r
-}\r
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.util.concurrent.Future;
-
-public class Bug50805 extends DefaultTestCase {
- public Bug50805(String name) {
- super(name);
- }
-
- public void test50805() throws Exception {
- init();
- this.datasource.setInitialSize(0);
- this.datasource.setMaxActive(10);
- this.datasource.setMinIdle(1);
-
- assertEquals("Current size should be 0.", 0, this.datasource.getSize());
-
- this.datasource.getConnection().close();
-
- assertEquals("Current size should be 1.", 1, this.datasource.getSize());
- assertEquals("Idle size should be 1.", 1, this.datasource.getIdle());
- assertEquals("Busy size should be 0.", 0, this.datasource.getActive());
-
- Future<Connection> fc = this.datasource.getConnectionAsync();
-
- Connection con = fc.get();
-
- assertEquals("Current size should be 1.", 1, this.datasource.getSize());
- assertEquals("Idle size should be 0.", 0, this.datasource.getIdle());
- assertEquals("Busy size should be 1.", 1, this.datasource.getActive());
-
- con.close();
- assertEquals("Current size should be 1.", 1, this.datasource.getSize());
- assertEquals("Idle size should be 1.", 1, this.datasource.getIdle());
- assertEquals("Busy size should be 0.", 0, this.datasource.getActive());
- }
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.sql.Statement;
-import java.sql.ResultSet;
-
-import javax.sql.DataSource;
-
-
-/**
- * @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.datasource.getPoolProperties().setFairQueue(false);
- 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 = 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 testPoolThreads10Connections10Fair() throws Exception {
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.datasource.getPoolProperties().setFairQueue(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-"+i);
- t.d = this.datasource;
- t.start();
- }
- latch.await();
- long delta = System.currentTimeMillis() - start;
- System.out.println("[testPoolThreads10Connections10Fair]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
- tearDown();
- }
-
-// public void testC3P0Threads10Connections10() throws Exception {
-// init();
-// this.datasource.getPoolProperties().setMaxActive(10);
-// this.threadcount = 10;
-// this.transferPropertiesToC3P0();
-// this.c3p0Datasource.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 = this.c3p0Datasource;
-// t.start();
-// }
-// latch.await();
-// long delta = System.currentTimeMillis() - start;
-// System.out.println("[testC3P0Threads10Connections10]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.datasource.getPoolProperties().setFairQueue(false);
- 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 = 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 testPoolThreads20Connections10Fair() throws Exception {
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.datasource.getPoolProperties().setFairQueue(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-"+i);
- t.d = this.datasource;
- t.start();
- }
- latch.await();
- long delta = System.currentTimeMillis() - start;
- System.out.println("[testPoolThreads20Connections10Fair]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
- tearDown();
- }
-
-// public void testC3P0Threads20Connections10() throws Exception {
-// init();
-// this.datasource.getPoolProperties().setMaxActive(10);
-// this.threadcount = 20;
-// this.transferPropertiesToC3P0();
-// this.c3p0Datasource.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 = this.c3p0Datasource;
-// t.start();
-// }
-// latch.await();
-// long delta = System.currentTimeMillis() - start;
-// System.out.println("[testC3P0Threads20Connections10]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
-// tearDown();
-// }
-
- public void testDBCPThreads10Connections10Validate() throws Exception {
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- 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().setTestOnBorrow(true);
- this.datasource.getPoolProperties().setFairQueue(false);
- 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 = 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 testPoolThreads10Connections10ValidateFair() throws Exception {
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.datasource.getPoolProperties().setTestOnBorrow(true);
- this.datasource.getPoolProperties().setFairQueue(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 = this.datasource;
- t.start();
- }
- latch.await();
- long delta = System.currentTimeMillis() - start;
- System.out.println("[testPoolThreads10Connections10ValidateFair]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
- tearDown();
- }
-
-// public void testC3P0Threads10Connections10Validate() throws Exception {
-// init();
-// this.datasource.getPoolProperties().setMaxActive(10);
-// this.datasource.getPoolProperties().setTestOnBorrow(true);
-// this.threadcount = 10;
-// this.transferPropertiesToC3P0();
-// this.c3p0Datasource.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 = this.c3p0Datasource;
-// t.start();
-// }
-// latch.await();
-// long delta = System.currentTimeMillis() - start;
-// System.out.println("[testC3P0Threads10Connections10Validate]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
-// tearDown();
-// }
-
- public void testDBCPThreads20Connections10Validate() throws Exception {
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- 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().setTestOnBorrow(true);
- this.datasource.getPoolProperties().setFairQueue(false);
- 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 = 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 void testPoolThreads10Connections20ValidateFair() throws Exception {
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.datasource.getPoolProperties().setTestOnBorrow(true);
- this.datasource.getPoolProperties().setFairQueue(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 = this.datasource;
- t.start();
- }
- latch.await();
- long delta = System.currentTimeMillis() - start;
- System.out.println("[testPoolThreads20Connections10ValidateFair]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
- tearDown();
- }
-
-// public void testC3P0Threads10Connections20Validate() throws Exception {
-// init();
-// this.datasource.getPoolProperties().setMaxActive(10);
-// this.datasource.getPoolProperties().setTestOnBorrow(true);
-// this.threadcount = 20;
-// this.transferPropertiesToC3P0();
-// this.c3p0Datasource.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 = this.c3p0Datasource;
-// t.start();
-// }
-// latch.await();
-// long delta = System.currentTimeMillis() - start;
-// System.out.println("[testC3P0Threads10Connections20Validate]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
-// tearDown();
-// }
-
- public class TestThread extends Thread {
- protected DataSource d;
- protected String query = null;
- @Override
- 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++;
- if (query!=null) {
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery(query);
- while (rs.next()) {
- }
- rs.close();
- st.close();
- }
- } 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:"+(max/1000f/1000f)+" ms."+
- "\n\tTotal time to retrieve connection:"+(totalmax/1000f/1000f)+" ms."+
- "\n\tAverage time to retrieve connection:"+(totalmax/1000f/1000f)/nroffetch+" ms."+
- "\n\tMax time to close connection:"+(cmax/1000f/1000f)+" ms."+
- "\n\tTotal time to close connection:"+(totalcmax/1000f/1000f)+" ms."+
- "\n\tAverage time to close connection:"+(totalcmax/1000f/1000f)/nroffetch+" ms."+
- "\n\tRun time:"+(totalruntime/1000f/1000f)+" ms."+
- "\n\tNr of fetch:"+nroffetch);
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.Future;
-import java.util.concurrent.TimeUnit;
-import java.sql.Connection;
-import java.sql.Statement;
-import java.sql.ResultSet;
-
-import javax.sql.DataSource;
-
-import org.apache.tomcat.jdbc.pool.DataSourceProxy;
-import org.apache.tomcat.jdbc.test.driver.Driver;
-
-/**
- * @author Filip Hanik
- * @version 1.0
- */
-public class ConnectCountTest extends DefaultTestCase {
- public ConnectCountTest(String name) {
- super(name);
- }
-
- protected boolean run = true;
- protected long sleep = Long.getLong("sleep", 10);
- protected long complete = Long.getLong("complete",20000);
- protected boolean printthread = Boolean.getBoolean("printthread");
- CountDownLatch latch = null;
-
-
- @Override
- public org.apache.tomcat.jdbc.pool.DataSource createDefaultDataSource() {
- // TODO Auto-generated method stub
- org.apache.tomcat.jdbc.pool.DataSource ds = super.createDefaultDataSource();
- ds.getPoolProperties().setDriverClassName(Driver.class.getName());
- ds.getPoolProperties().setUrl(Driver.url);
- ds.getPoolProperties().setInitialSize(0);
- ds.getPoolProperties().setMaxIdle(10);
- ds.getPoolProperties().setMinIdle(10);
- ds.getPoolProperties().setMaxActive(10);
- return ds;
- }
-
-
- @Override
- protected void tearDown() throws Exception {
- Driver.reset();
- super.tearDown();
- }
-
-
- protected void printThreadResults(TestThread[] threads, String name, int active, int expected) {
- long minfetch = Long.MAX_VALUE, maxfetch = Long.MIN_VALUE, totalfetch = 0;
- long maxwait = 0, minwait = Long.MAX_VALUE, averagewait = 0, totalwait = 0;
- float avgfetch = 0;
- for (int i=0; i<threads.length; i++) {
- TestThread t = threads[i];
- totalfetch += t.nroffetch;
- totalwait += t.totalwait;
- maxwait = Math.max(maxwait,t.maxwait);
- minwait = Math.min(minwait, t.minwait);
- minfetch = Math.min(minfetch, t.nroffetch);
- maxfetch = Math.max(maxfetch, t.nroffetch);
- if (ConnectCountTest.this.printthread)
- System.out.println(t.getName()+" : Nr-of-fetch:"+t.nroffetch+ " Max fetch Time:"+(((float)t.maxwait)/1000000f)+"ms. :Max close time:"+(((float)t.cmax)/1000000f)+"ms.");
- }
- System.out.println("["+name+"] Max fetch:"+(maxfetch)+" Min fetch:"+(minfetch)+" Average fetch:"+
- (((float)totalfetch))/(float)threads.length);
- System.out.println("["+name+"] Max wait:"+(((float)maxwait)/1000000f)+"ms. Min wait:"+(((float)minwait)/1000000f)+"ms. Average wait:"+(((((float)totalwait))/(float)totalfetch)/1000000f)+" ms.");
- System.out.println("["+name+"] Max active:"+active+" Expected Active:"+expected);
-
-
- }
-
- public void testDBCPThreads20Connections10() throws Exception {
- System.out.println("[testDBCPThreads20Connections10] Starting fairness - DBCP");
- this.threadcount = 20;
- init();
- this.transferProperties();
- this.tDatasource.getConnection().close();
- latch = new CountDownLatch(threadcount);
- long start = System.currentTimeMillis();
- TestThread[] threads = new TestThread[threadcount];
- for (int i=0; i<threadcount; i++) {
- threads[i] = new TestThread();
- threads[i].setName("tomcat-dbcp-"+i);
- threads[i].d = this.tDatasource;
-
- }
- for (int i=0; i<threadcount; i++) {
- threads[i].start();
- }
- if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
- System.out.println("Latch timed out.");
- }
- this.run = false;
- long delta = System.currentTimeMillis() - start;
- printThreadResults(threads,"testDBCPThreads20Connections10",Driver.connectCount.get(),10);
- tearDown();
- }
-
- public void testPoolThreads20Connections10() throws Exception {
- System.out.println("[testPoolThreads20Connections10] Starting fairness - Tomcat JDBC - Non Fair");
- init();
- this.threadcount = 20;
- this.transferProperties();
- this.datasource.getConnection().close();
- latch = new CountDownLatch(threadcount);
- long start = System.currentTimeMillis();
- TestThread[] threads = new TestThread[threadcount];
- for (int i=0; i<threadcount; i++) {
- threads[i] = new TestThread();
- threads[i].setName("tomcat-pool-"+i);
- threads[i].d = this.datasource;
-
- }
- for (int i=0; i<threadcount; i++) {
- threads[i].start();
- }
- if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
- System.out.println("Latch timed out.");
- }
- this.run = false;
- long delta = System.currentTimeMillis() - start;
- printThreadResults(threads,"testPoolThreads20Connections10",Driver.connectCount.get(),10);
- tearDown();
-
- }
-
- public void testPoolThreads20Connections10Fair() throws Exception {
- System.out.println("[testPoolThreads20Connections10Fair] Starting fairness - Tomcat JDBC - Fair");
- init();
- this.threadcount = 20;
- this.datasource.getPoolProperties().setFairQueue(true);
- this.transferProperties();
- this.datasource.getConnection().close();
- latch = new CountDownLatch(threadcount);
- long start = System.currentTimeMillis();
- TestThread[] threads = new TestThread[threadcount];
- for (int i=0; i<threadcount; i++) {
- threads[i] = new TestThread();
- threads[i].setName("tomcat-pool-"+i);
- threads[i].d = this.datasource;
-
- }
- for (int i=0; i<threadcount; i++) {
- threads[i].start();
- }
- if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
- System.out.println("Latch timed out.");
- }
- this.run = false;
- long delta = System.currentTimeMillis() - start;
- printThreadResults(threads,"testPoolThreads20Connections10Fair",Driver.connectCount.get(),10);
- tearDown();
- }
-
- public void testPoolThreads20Connections10FairAsync() throws Exception {
- System.out.println("[testPoolThreads20Connections10FairAsync] Starting fairness - Tomcat JDBC - Fair - Async");
- init();
- this.threadcount = 20;
- this.datasource.getPoolProperties().setFairQueue(true);
- this.datasource.getPoolProperties().setInitialSize(this.datasource.getPoolProperties().getMaxActive());
- this.transferProperties();
- this.datasource.getConnection().close();
- latch = new CountDownLatch(threadcount);
- long start = System.currentTimeMillis();
- TestThread[] threads = new TestThread[threadcount];
- for (int i=0; i<threadcount; i++) {
- threads[i] = new TestThread();
- threads[i].setName("tomcat-pool-"+i);
- threads[i].async = true;
- threads[i].d = this.datasource;
-
- }
- for (int i=0; i<threadcount; i++) {
- threads[i].start();
- }
- if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
- System.out.println("Latch timed out.");
- }
- this.run = false;
- long delta = System.currentTimeMillis() - start;
- printThreadResults(threads,"testPoolThreads20Connections10FairAsync",Driver.connectCount.get(),10);
- tearDown();
- }
-
-// public void testC3P0Threads20Connections10() throws Exception {
-// System.out.println("[testC3P0Threads20Connections10] Starting fairness - C3P0");
-// init();
-// this.threadcount = 20;
-// this.transferPropertiesToC3P0();
-// this.datasource.getConnection().close();
-// latch = new CountDownLatch(threadcount);
-// long start = System.currentTimeMillis();
-// TestThread[] threads = new TestThread[threadcount];
-// for (int i=0; i<threadcount; i++) {
-// threads[i] = new TestThread();
-// threads[i].setName("tomcat-pool-"+i);
-// threads[i].d = this.c3p0Datasource;
-//
-// }
-// for (int i=0; i<threadcount; i++) {
-// threads[i].start();
-// }
-// if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
-// System.out.println("Latch timed out.");
-// }
-// this.run = false;
-// long delta = System.currentTimeMillis() - start;
-// printThreadResults(threads,"testC3P0Threads20Connections10",Driver.connectCount.get(),10);
-// tearDown();
-//
-// }
-
-
- public class TestThread extends Thread {
- protected DataSource d;
- protected String query = null;
- protected long sleep = 10;
- protected boolean async = false;
- long minwait = Long.MAX_VALUE, maxwait = -1, totalwait=0, totalcmax=0, cmax = -1, nroffetch = 0, totalruntime = 0;
- @Override
- public void run() {
- try {
- long now = System.currentTimeMillis();
- while (ConnectCountTest.this.run) {
- if ((System.currentTimeMillis()-now)>=ConnectCountTest.this.complete) break;
- long start = System.nanoTime();
- Connection con = null;
- try {
- if (async) {
- Future<Connection> cf = ((DataSourceProxy)d).getConnectionAsync();
- con = cf.get();
- } else {
- con = d.getConnection();
- }
- long delta = System.nanoTime() - start;
- totalwait += delta;
- maxwait = Math.max(delta, maxwait);
- minwait = Math.min(delta, minwait);
- nroffetch++;
- if (query!=null) {
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery(query);
- while (rs.next()) {
- }
- rs.close();
- st.close();
- }
- try {
- if (ConnectCountTest.this.sleep>0) sleep(ConnectCountTest.this.sleep);
- } catch (InterruptedException x) {
- interrupted();
- }
- } 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 {
- ConnectCountTest.this.latch.countDown();
- }
- if (System.getProperty("print-thread-stats")!=null) {
- System.out.println("["+getName()+"] "+
- "\n\tMax time to retrieve connection:"+(((float)maxwait)/1000f/1000f)+" ms."+
- "\n\tTotal time to retrieve connection:"+(((float)totalwait)/1000f/1000f)+" ms."+
- "\n\tAverage time to retrieve connection:"+(((float)totalwait)/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);
- }
- }
- }
-}
-
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.Statement;
-import java.util.Random;
-import java.sql.ResultSet;
-
-import org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer;
-
-public class CreateTestTable extends DefaultTestCase {
-
- public static volatile boolean recreate = Boolean.getBoolean("recreate");
-
- public CreateTestTable(String name) {
- super(name);
- }
-
- public void testCreateTestTable() throws Exception {
- this.init();
- Connection con = datasource.getConnection();
- Statement st = con.createStatement();
- try {
- st.execute("create table test(id int not null, val1 varchar(255), val2 varchar(255), val3 varchar(255), val4 varchar(255))");
- }catch (Exception ignore) {}
- st.close();
- con.close();
- }
-
- public int testCheckData() throws Exception {
- int count = 0;
- String check = "select count (*) from test";
- this.init();
- Connection con = datasource.getConnection();
- Statement st = con.createStatement();
- try {
- ResultSet rs = st.executeQuery(check);
-
- if (rs.next())
- count = rs.getInt(1);
- rs.close();
- st.close();
- System.out.println("Count:"+count);
- }catch (Exception ignore) {}
- con.close();
- return count;
- }
-
- public void testPopulateData() throws Exception {
- int count = 100000;
- int actual = testCheckData();
- if (actual>=count) {
- System.out.println("Test tables has "+actual+" rows of data. No need to populate.");
- return;
- }
-
- datasource.setJdbcInterceptors(ResetAbandonedTimer.class.getName());
- String insert = "insert into test values (?,?,?,?,?)";
- this.init();
- this.datasource.setRemoveAbandoned(false);
- Connection con = datasource.getConnection();
-
- boolean commit = con.getAutoCommit();
- con.setAutoCommit(false);
- if (recreate) {
- Statement st = con.createStatement();
- try {
- st.execute("drop table test");
- }catch (Exception ignore) {}
- st.execute("create table test(id int not null, val1 varchar(255), val2 varchar(255), val3 varchar(255), val4 varchar(255))");
- st.close();
- }
-
-
- PreparedStatement ps = con.prepareStatement(insert);
- ps.setQueryTimeout(0);
- for (int i=actual; i<count; i++) {
- ps.setInt(1,i);
- String s = getRandom();
- ps.setString(2, s);
- ps.setString(3, s);
- ps.setString(4, s);
- ps.setString(5, s);
- ps.addBatch();
- ps.clearParameters();
- if ((i+1) % 1000 == 0) {
- System.out.print(".");
- }
- if ((i+1) % 10000 == 0) {
- System.out.print("\n"+(i+1));
- ps.executeBatch();
- ps.close();
- con.commit();
- ps = con.prepareStatement(insert);
- ps.setQueryTimeout(0);
- }
-
- }
- ps.close();
- con.setAutoCommit(commit);
- con.close();
- }
-
- public static Random random = new Random(System.currentTimeMillis());
- public static String getRandom() {
- StringBuilder s = new StringBuilder(256);
- for (int i=0;i<254; i++) {
- int b = Math.abs(random.nextInt() % 29);
- char c = (char)(b+65);
- s.append(c);
- }
- return s.toString();
- }
-
- public static void main(String[] args) throws Exception {
- recreate = true;
- CreateTestTable test = new CreateTestTable("CreateTestTable");
- test.testPopulateData();
- }
-
-}
+++ /dev/null
-/*
- * 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();
-
- //mysql
- //url = System.getProperty("url","jdbc:mysql://localhost:3306/mysql?autoReconnect=true");
- //driverClassName = System.getProperty("driverClassName","com.mysql.jdbc.Driver");
-
- //derby
- //url = System.getProperty("url","jdbc:derby:derbyDB;create=true");
- //driverClassName = System.getProperty("driverClassName","org.apache.derby.jdbc.EmbeddedDriver");
-
- url = System.getProperty("url","jdbc:h2:~/.h2/test;QUERY_TIMEOUT=0;DB_CLOSE_ON_EXIT=FALSE");
- driverClassName = System.getProperty("driverClassName","org.h2.Driver");
- System.setProperty("h2.serverCachedObjects", "10000");
-
- password = System.getProperty("password","password");
- username = System.getProperty("username","root");
-
- validationQuery = System.getProperty("validationQuery","SELECT 1");
- defaultAutoCommit = true;
- defaultReadOnly = false;
- defaultTransactionIsolation = DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION;
- connectionProperties = null;
- defaultCatalog = null;
- initialSize = 10;
- maxActive = 100;
- maxIdle = initialSize;
- minIdle = initialSize;
- maxWait = 10000;
-
- testOnBorrow = true;
- testOnReturn = false;
- testWhileIdle = true;
- timeBetweenEvictionRunsMillis = 5000;
- numTestsPerEvictionRun = 0;
- minEvictableIdleTimeMillis = 1000;
- removeAbandoned = true;
- removeAbandonedTimeout = 5000;
- logAbandoned = true;
- validationInterval = 0; //always validate
- initSQL = null;
- testOnConnect = false;;
- dbProperties.setProperty("user",username);
- dbProperties.setProperty("password",password);
- }
-}
+++ /dev/null
-/*
- * 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 junit.framework.TestCase;
-
-import org.apache.tomcat.dbcp.dbcp.BasicDataSource;
-import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;
-import org.apache.tomcat.jdbc.pool.PoolConfiguration;
-import org.apache.tomcat.jdbc.pool.PoolProperties;
-
-//import com.mchange.v2.c3p0.ComboPooledDataSource;
-//import com.mchange.v2.log.MLevel;
-//import com.mchange.v2.log.MLog;
-
-/**
- * @author Filip Hanik
- * @version 1.0
- */
-public class DefaultTestCase extends TestCase {
- protected org.apache.tomcat.jdbc.pool.DataSource datasource;
- protected BasicDataSource tDatasource;
-// protected ComboPooledDataSource c3p0Datasource;
- protected int threadcount = 10;
- protected int iterations = 100000;
- public DefaultTestCase(String name) {
- super(name);
- }
-
- @Override
- public void setUp() throws Exception {
- init();
- }
-
- public org.apache.tomcat.jdbc.pool.DataSource createDefaultDataSource() {
- org.apache.tomcat.jdbc.pool.DataSource datasource = null;
- PoolConfiguration p = new DefaultProperties();
- p.setFairQueue(false);
- 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(10);
- p.setMinEvictableIdleTimeMillis(10000);
- p.setMinIdle(threadcount);
- p.setLogAbandoned(false);
- p.setRemoveAbandoned(false);
- datasource = new org.apache.tomcat.jdbc.pool.DataSource();
- datasource.setPoolProperties(p);
- return datasource;
- }
-
- protected void init() throws Exception {
- this.datasource = createDefaultDataSource();
- }
-
- protected void transferProperties() {
- try {
- Properties p = new Properties();
- for (int i=0; i< 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) BasicDataSourceFactory.createDataSource(p);
- }catch (Exception x) {
- x.printStackTrace();
- }
- }
-
- protected void transferPropertiesToC3P0() throws Exception {
-// System.setProperty("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "WARNING");
-// MLog.getLogger().setLevel(MLevel.WARNING);
-// MLog.getLogger("com").setLevel(MLevel.WARNING);
-// //http://www.mchange.com/projects/c3p0/index.html#automaticTestTable
-// ComboPooledDataSource c3p0 = new ComboPooledDataSource();
-// c3p0.setAcquireIncrement(1);
-// c3p0.setAcquireRetryAttempts(2);
-// c3p0.setAcquireRetryDelay(datasource.getPoolProperties().getMaxWait());
-// c3p0.setCheckoutTimeout(datasource.getPoolProperties().getMaxWait());
-// c3p0.setDebugUnreturnedConnectionStackTraces(datasource.getPoolProperties().isLogAbandoned());
-// c3p0.setIdleConnectionTestPeriod(datasource.getPoolProperties().getTimeBetweenEvictionRunsMillis()/1000);
-// c3p0.setInitialPoolSize(datasource.getPoolProperties().getInitialSize());
-// c3p0.setMaxIdleTime(datasource.getPoolProperties().getMinEvictableIdleTimeMillis()/1000);
-// c3p0.setMaxIdleTimeExcessConnections(datasource.getPoolProperties().getMaxIdle());
-// c3p0.setMaxPoolSize(datasource.getPoolProperties().getMaxActive());
-// c3p0.setMinPoolSize(datasource.getPoolProperties().getMinIdle());
-// c3p0.setPassword(datasource.getPoolProperties().getPassword());
-// c3p0.setPreferredTestQuery(datasource.getPoolProperties().getValidationQuery());
-// c3p0.setTestConnectionOnCheckin(datasource.getPoolProperties().isTestOnReturn());
-// c3p0.setTestConnectionOnCheckout(datasource.getPoolProperties().isTestOnBorrow());
-// c3p0.setUnreturnedConnectionTimeout(datasource.getPoolProperties().getRemoveAbandonedTimeout());
-// c3p0.setUser(datasource.getPoolProperties().getUsername());
-// c3p0.setUsesTraditionalReflectiveProxies(true);
-// c3p0.setJdbcUrl(datasource.getPoolProperties().getUrl());
-// c3p0.setDriverClass(datasource.getPoolProperties().getDriverClassName());
-// this.c3p0Datasource = c3p0;
-
- /**
- acquireIncrement
- acquireRetryAttempts
- acquireRetryDelay
- autoCommitOnClose
- automaticTestTable
- breakAfterAcquireFailure
- checkoutTimeout
- connectionCustomizerClassName
- connectionTesterClassName
- debugUnreturnedConnectionStackTraces
- factoryClassLocation
- forceIgnoreUnresolvedTransactions
- idleConnectionTestPeriod
- initialPoolSize
- maxAdministrativeTaskTime
- maxConnectionAge
- maxIdleTime
- maxIdleTimeExcessConnections
- maxPoolSize
- maxStatements
- maxStatementsPerConnection
- minPoolSize
- numHelperThreads
- overrideDefaultUser
- overrideDefaultPassword
- password
- preferredTestQuery
- propertyCycle
- testConnectionOnCheckin
- testConnectionOnCheckout
- unreturnedConnectionTimeout
- user
- usesTraditionalReflectiveProxies
- */
- }
-
-
- @Override
- protected void tearDown() throws Exception {
- try {datasource.close();}catch(Exception ignore){}
- try {tDatasource.close();}catch(Exception ignore){}
- //try {((ComboPooledDataSource)c3p0Datasource).close(true);}catch(Exception ignore){}
- datasource = null;
- tDatasource = null;
- //c3p0Datasource = null;
- System.gc();
- org.apache.tomcat.jdbc.test.driver.Driver.reset();
- }
-
- 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
- };
-
-
-
-}
+++ /dev/null
-/*
- * 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.Future;
-import java.util.concurrent.TimeUnit;
-import java.sql.Connection;
-import java.sql.Statement;
-import java.sql.ResultSet;
-
-import javax.sql.DataSource;
-
-import org.apache.tomcat.jdbc.pool.DataSourceProxy;
-
-/**
- * @author Filip Hanik
- * @version 1.0
- */
-public class FairnessTest extends DefaultTestCase {
- public FairnessTest(String name) {
- super(name);
- }
-
- protected boolean run = true;
- protected long sleep = Long.getLong("sleep", 10);
- protected long complete = Long.getLong("complete",20000);
- protected boolean printthread = Boolean.getBoolean("printthread");
- CountDownLatch latch = null;
- protected void printThreadResults(TestThread[] threads, String name, int active, int expected) {
- long minfetch = Long.MAX_VALUE, maxfetch = Long.MIN_VALUE, totalfetch = 0;
- long maxwait = 0, minwait = Long.MAX_VALUE, averagewait = 0, totalwait = 0;
- float avgfetch = 0;
- for (int i=0; i<threads.length; i++) {
- TestThread t = threads[i];
- totalfetch += t.nroffetch;
- totalwait += t.totalwait;
- maxwait = Math.max(maxwait,t.maxwait);
- minwait = Math.min(minwait, t.minwait);
- minfetch = Math.min(minfetch, t.nroffetch);
- maxfetch = Math.max(maxfetch, t.nroffetch);
- if (FairnessTest.this.printthread)
- System.out.println(t.getName()+" : Nr-of-fetch:"+t.nroffetch+ " Max fetch Time:"+(((float)t.maxwait)/1000000f)+"ms. :Max close time:"+(((float)t.cmax)/1000000f)+"ms.");
- }
- System.out.println("["+name+"] Max fetch:"+(maxfetch)+" Min fetch:"+(minfetch)+" Average fetch:"+
- (((float)totalfetch))/(float)threads.length);
- System.out.println("["+name+"] Max wait:"+(((float)maxwait)/1000000f)+"ms. Min wait:"+(((float)minwait)/1000000f)+"ms. Average wait:"+(((((float)totalwait))/(float)totalfetch)/1000000f)+" ms.");
- System.out.println("["+name+"] Max active:"+active+" Expected Active:"+expected);
-
-
- }
-
- public void testDBCPThreads20Connections10() throws Exception {
- System.out.println("[testDBCPThreads20Connections10] Starting fairness - DBCP");
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.threadcount = 20;
- this.transferProperties();
- this.tDatasource.getConnection().close();
- latch = new CountDownLatch(threadcount);
- long start = System.currentTimeMillis();
- TestThread[] threads = new TestThread[threadcount];
- for (int i=0; i<threadcount; i++) {
- threads[i] = new TestThread();
- threads[i].setName("tomcat-dbcp-"+i);
- threads[i].d = this.tDatasource;
-
- }
- for (int i=0; i<threadcount; i++) {
- threads[i].start();
- }
- if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
- System.out.println("Latch timed out.");
- }
- this.run = false;
- long delta = System.currentTimeMillis() - start;
- printThreadResults(threads,"testDBCPThreads20Connections10",this.tDatasource.getNumActive(),10);
- tearDown();
- }
-
- public void testPoolThreads20Connections10() throws Exception {
- System.out.println("[testPoolThreads20Connections10] Starting fairness - Tomcat JDBC - Non Fair");
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.datasource.getPoolProperties().setFairQueue(false);
- this.threadcount = 20;
- this.transferProperties();
- this.datasource.getConnection().close();
- latch = new CountDownLatch(threadcount);
- long start = System.currentTimeMillis();
- TestThread[] threads = new TestThread[threadcount];
- for (int i=0; i<threadcount; i++) {
- threads[i] = new TestThread();
- threads[i].setName("tomcat-pool-"+i);
- threads[i].d = this.datasource;
-
- }
- for (int i=0; i<threadcount; i++) {
- threads[i].start();
- }
- if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
- System.out.println("Latch timed out.");
- }
- this.run = false;
- long delta = System.currentTimeMillis() - start;
- printThreadResults(threads,"testPoolThreads20Connections10",this.datasource.getSize(),10);
- tearDown();
-
- }
-
- public void testPoolThreads20Connections10Fair() throws Exception {
- System.out.println("[testPoolThreads20Connections10Fair] Starting fairness - Tomcat JDBC - Fair");
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.datasource.getPoolProperties().setFairQueue(true);
- this.threadcount = 20;
- this.transferProperties();
- this.datasource.getConnection().close();
- latch = new CountDownLatch(threadcount);
- long start = System.currentTimeMillis();
- TestThread[] threads = new TestThread[threadcount];
- for (int i=0; i<threadcount; i++) {
- threads[i] = new TestThread();
- threads[i].setName("tomcat-pool-"+i);
- threads[i].d = this.datasource;
-
- }
- for (int i=0; i<threadcount; i++) {
- threads[i].start();
- }
- if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
- System.out.println("Latch timed out.");
- }
- this.run = false;
- long delta = System.currentTimeMillis() - start;
- printThreadResults(threads,"testPoolThreads20Connections10Fair",this.datasource.getSize(),10);
- tearDown();
- }
-
- public void testPoolThreads20Connections10FairAsync() throws Exception {
- System.out.println("[testPoolThreads20Connections10FairAsync] Starting fairness - Tomcat JDBC - Fair - Async");
- init();
- this.datasource.getPoolProperties().setMaxActive(10);
- this.datasource.getPoolProperties().setFairQueue(true);
- this.threadcount = 20;
- this.transferProperties();
- this.datasource.getConnection().close();
- latch = new CountDownLatch(threadcount);
- long start = System.currentTimeMillis();
- TestThread[] threads = new TestThread[threadcount];
- for (int i=0; i<threadcount; i++) {
- threads[i] = new TestThread();
- threads[i].setName("tomcat-pool-"+i);
- threads[i].async = true;
- threads[i].d = this.datasource;
-
- }
- for (int i=0; i<threadcount; i++) {
- threads[i].start();
- }
- if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
- System.out.println("Latch timed out.");
- }
- this.run = false;
- long delta = System.currentTimeMillis() - start;
- printThreadResults(threads,"testPoolThreads20Connections10FairAsync",this.datasource.getSize(),10);
- tearDown();
- }
-
-// public void testC3P0Threads20Connections10() throws Exception {
-// System.out.println("[testC3P0Threads20Connections10] Starting fairness - C3P0");
-// init();
-// this.datasource.getPoolProperties().setMaxActive(10);
-// this.datasource.getPoolProperties().setFairQueue(false);
-// this.threadcount = 20;
-// this.transferPropertiesToC3P0();
-// this.datasource.getConnection().close();
-// latch = new CountDownLatch(threadcount);
-// long start = System.currentTimeMillis();
-// TestThread[] threads = new TestThread[threadcount];
-// for (int i=0; i<threadcount; i++) {
-// threads[i] = new TestThread();
-// threads[i].setName("tomcat-pool-"+i);
-// threads[i].d = this.c3p0Datasource;
-//
-// }
-// for (int i=0; i<threadcount; i++) {
-// threads[i].start();
-// }
-// if (!latch.await(complete+1000,TimeUnit.MILLISECONDS)) {
-// System.out.println("Latch timed out.");
-// }
-// this.run = false;
-// long delta = System.currentTimeMillis() - start;
-// printThreadResults(threads,"testC3P0Threads20Connections10",c3p0Datasource.getNumConnectionsAllUsers(),10);
-// tearDown();
-//
-// }
-
-
- public class TestThread extends Thread {
- protected DataSource d;
- protected String query = null;
- protected long sleep = 10;
- protected boolean async = false;
- long minwait = Long.MAX_VALUE, maxwait = -1, totalwait=0, totalcmax=0, cmax = -1, nroffetch = 0, totalruntime = 0;
- @Override
- public void run() {
- try {
- long now = System.currentTimeMillis();
- while (FairnessTest.this.run) {
- if ((System.currentTimeMillis()-now)>=FairnessTest.this.complete) break;
- long start = System.nanoTime();
- Connection con = null;
- try {
- if (async) {
- Future<Connection> cf = ((DataSourceProxy)d).getConnectionAsync();
- con = cf.get();
- } else {
- con = d.getConnection();
- }
- long delta = System.nanoTime() - start;
- totalwait += delta;
- maxwait = Math.max(delta, maxwait);
- minwait = Math.min(delta, minwait);
- nroffetch++;
- if (query!=null) {
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery(query);
- while (rs.next()) {
- }
- rs.close();
- st.close();
- }
- try {
- if (FairnessTest.this.sleep>0) sleep(FairnessTest.this.sleep);
- } catch (InterruptedException x) {
- interrupted();
- }
- } 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 {
- FairnessTest.this.latch.countDown();
- }
- if (System.getProperty("print-thread-stats")!=null) {
- System.out.println("["+getName()+"] "+
- "\n\tMax time to retrieve connection:"+(((float)maxwait)/1000f/1000f)+" ms."+
- "\n\tTotal time to retrieve connection:"+(((float)totalwait)/1000f/1000f)+" ms."+
- "\n\tAverage time to retrieve connection:"+(((float)totalwait)/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);
- }
- }
- }
-}
-
+++ /dev/null
-/*
- * 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.management.ManagementFactory;
-import java.util.Hashtable;
-import java.util.Properties;
-
-import javax.management.JMX;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.PoolUtilities;
-import org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean;
-import org.apache.tomcat.jdbc.test.driver.Driver;
-
-public class JmxPasswordTest extends DefaultTestCase{
- public static final String password = "password";
- public static final String username = "username";
- public static ObjectName oname = null;
-
- public JmxPasswordTest(String s) {
- super(s);
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- this.datasource.setDriverClassName(Driver.class.getName());
- this.datasource.setUrl("jdbc:tomcat:test");
- this.datasource.setPassword(password);
- this.datasource.setUsername(username);
- this.datasource.getConnection().close();
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- String domain = "tomcat.jdbc";
- Hashtable<String,String> properties = new Hashtable<String,String>();
- properties.put("type", "ConnectionPool");
- properties.put("class", this.getClass().getName());
- oname = new ObjectName(domain,properties);
- ConnectionPool pool = datasource.createPool();
- org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool = new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(pool);
- mbs.registerMBean(jmxPool, oname);
-
- }
-
- public void testPassword() throws Exception {
- assertEquals("Passwords should match when not using JMX.",password,datasource.getPoolProperties().getPassword());
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- ConnectionPoolMBean mbean = JMX.newMBeanProxy(mbs, oname, ConnectionPoolMBean.class);
- String jmxPassword = mbean.getPassword();
- Properties jmxProperties = mbean.getDbProperties();
- assertFalse("Passwords should not match.", password.equals(jmxPassword));
- assertFalse("Password property should be missing", jmxProperties.containsKey(PoolUtilities.PROP_PASSWORD));
- }
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.Statement;
-import java.util.concurrent.Future;
-
-import org.apache.tomcat.jdbc.pool.DataSource;
-import org.apache.tomcat.jdbc.pool.PoolConfiguration;
-import org.apache.tomcat.jdbc.pool.PoolProperties;
-
-public class SimplePOJOAsyncExample {
-
- public static void main(String[] args) throws Exception {
- PoolConfiguration p = new PoolProperties();
- p.setFairQueue(true);
- p.setUrl("jdbc:mysql://localhost:3306/mysql?autoReconnect=true");
- p.setDriverClassName("com.mysql.jdbc.Driver");
- p.setUsername("root");
- p.setPassword("password");
- p.setJmxEnabled(true);
- p.setTestWhileIdle(false);
- p.setTestOnBorrow(true);
- p.setValidationQuery("SELECT 1");
- p.setTestOnReturn(false);
- p.setValidationInterval(30000);
- p.setTimeBetweenEvictionRunsMillis(30000);
- p.setMaxActive(100);
- p.setInitialSize(10);
- p.setMaxWait(10000);
- p.setRemoveAbandonedTimeout(60);
- p.setMinEvictableIdleTimeMillis(30000);
- p.setMinIdle(10);
- p.setLogAbandoned(true);
- p.setRemoveAbandoned(true);
- p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
- DataSource datasource = new DataSource();
- datasource.setPoolProperties(p);
-
- Connection con = null;
- try {
- Future<Connection> future = datasource.getConnectionAsync();
- while (!future.isDone()) {
- System.out.println("Connection is not yet available. Do some background work");
- try {
- Thread.sleep(100); //simulate work
- }catch (InterruptedException x) {
- Thread.interrupted();
- }
- }
- con = future.get(); //should return instantly
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery("select * from user");
- int cnt = 1;
- while (rs.next()) {
- System.out.println((cnt++)+". Host:" +rs.getString("Host")+" User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
- }
- rs.close();
- st.close();
- } finally {
- if (con!=null) try {con.close();}catch (Exception ignore) {}
- }
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.Statement;
-
-import org.apache.tomcat.jdbc.pool.DataSource;
-import org.apache.tomcat.jdbc.pool.PoolConfiguration;
-import org.apache.tomcat.jdbc.pool.PoolProperties;
-
-public class SimplePOJOExample {
-
- public static void main(String[] args) throws Exception {
- PoolConfiguration p = new PoolProperties();
- p.setUrl("jdbc:mysql://localhost:3306/mysql?autoReconnect=true");
- p.setDriverClassName("com.mysql.jdbc.Driver");
- p.setUsername("root");
- p.setPassword("password");
- p.setJmxEnabled(true);
- p.setTestWhileIdle(false);
- p.setTestOnBorrow(true);
- p.setValidationQuery("SELECT 1");
- p.setTestOnReturn(false);
- p.setValidationInterval(30000);
- p.setTimeBetweenEvictionRunsMillis(30000);
- p.setMaxActive(100);
- p.setInitialSize(10);
- p.setMaxWait(10000);
- p.setRemoveAbandonedTimeout(60);
- p.setMinEvictableIdleTimeMillis(30000);
- p.setMinIdle(10);
- p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
- p.setLogAbandoned(true);
- p.setRemoveAbandoned(true);
- DataSource datasource = new DataSource();
- datasource.setPoolProperties(p);
-
- Connection con = null;
- try {
- con = datasource.getConnection();
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery("select * from user");
- int cnt = 1;
- while (rs.next()) {
- System.out.println((cnt++)+". Host:" +rs.getString("Host")+" User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
- }
- rs.close();
- st.close();
- } finally {
- if (con!=null) try {con.close();}catch (Exception ignore) {}
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.sql.SQLException;
-
-/**
- * If a connection is abandoned and closed,
- * then that should free up a spot in the pool, and other threads
- * that are waiting should not time out and throw an error but be
- * able to acquire a connection, since one was just released.
- * @author fhanik
- *
- */
-public class StarvationTest extends DefaultTestCase {
-
- public StarvationTest(String name) {
- super(name);
- }
-
- private void config() {
- datasource.getPoolProperties().setMaxActive(1);
- datasource.getPoolProperties().setMaxIdle(1);
- datasource.getPoolProperties().setInitialSize(1);
- datasource.getPoolProperties().setRemoveAbandoned(true);
- datasource.getPoolProperties().setRemoveAbandonedTimeout(5);
- datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(500);
- datasource.getPoolProperties().setMaxWait(10000);
- datasource.getPoolProperties().setLogAbandoned(true);
- }
-
-// public void testDBCPConnectionStarvation() throws Exception {
-// init();
-// config();
-// this.transferProperties();
-// this.tDatasource.getConnection().close();
-// javax.sql.DataSource datasource = this.tDatasource;
-// Connection con1 = datasource.getConnection();
-// Connection con2 = null;
-// try {
-// con2 = datasource.getConnection();
-// try {
-// con2.setCatalog("mysql");//make sure connection is valid
-// }catch (SQLException x) {
-// assertFalse("2nd Connection is not valid:"+x.getMessage(),true);
-// }
-// assertTrue("Connection 1 should be closed.",con1.isClosed()); //first connection should be closed
-// }catch (Exception x) {
-// assertFalse("Connection got starved:"+x.getMessage(),true);
-// }finally {
-// if (con2!=null) con2.close();
-// }
-//
-// }
-
- public void testConnectionStarvation() throws Exception {
- init();
- config();
- Connection con1 = datasource.getConnection();
- Connection con2 = null;
- try {
- con2 = datasource.getConnection();
- try {
- con2.setCatalog("mysql");//make sure connection is valid
- }catch (SQLException x) {
- assertFalse("2nd Connection is not valid:"+x.getMessage(),true);
- }
- assertTrue("Connection 1 should be closed.",con1.isClosed()); //first connection should be closed
- }catch (Exception x) {
- assertFalse("Connection got starved:"+x.getMessage(),true);
- }finally {
- if (con2!=null) con2.close();
- }
- }
-
- public void testFairConnectionStarvation() throws Exception {
- init();
- config();
- datasource.getPoolProperties().setFairQueue(true);
- Connection con1 = datasource.getConnection();
- Connection con2 = null;
- try {
- con2 = datasource.getConnection();
- try {
- con2.setCatalog("mysql");//make sure connection is valid
- }catch (SQLException x) {
- assertFalse("2nd Connection is not valid:"+x.getMessage(),true);
- }
- assertTrue("Connection 1 should be closed.",con1.isClosed()); //first connection should be closed
- }catch (Exception x) {
- assertFalse("Connection got starved:"+x.getMessage(),true);
- }finally {
- if (con2!=null) con2.close();
- }
- }
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.sql.Statement;
-
-import org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;
-
-public class StatementFinalizerTest extends DefaultTestCase {
-
- public StatementFinalizerTest(String name) {
- super(name);
- }
-
- public void testStatementFinalization() throws Exception {
- this.init();
- datasource.setJdbcInterceptors(StatementFinalizer.class.getName());
- Connection con = datasource.getConnection();
- Statement st = con.createStatement();
- assertFalse("Statement should not be closed.",st.isClosed());
- con.close();
- assertTrue("Statement should be closed.",st.isClosed());
- }
-
-}
+++ /dev/null
-/*
- * 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.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.apache.tomcat.jdbc.pool.FairBlockingQueue;
-
-import junit.framework.TestCase;
-
-public class TestAsyncQueue extends TestCase {
- protected FairBlockingQueue<Object> queue = null;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- this.queue = new FairBlockingQueue<Object>();
- }
-
- @Override
- protected void tearDown() throws Exception {
- this.queue = null;
- super.tearDown();
- }
-
-
- public void testAsyncPoll1() throws Exception {
- Object item = new Object();
- queue.offer(item);
- Future<Object> future = queue.pollAsync();
- assertEquals(future.get(),item);
- }
-
- public void testAsyncPoll2() throws Exception {
- Object item = new Object();
- OfferThread thread = new OfferThread(item,5000);
- thread.start();
- Future<Object> future = queue.pollAsync();
- try {
- future.get(2000, TimeUnit.MILLISECONDS);
- assertFalse("Request should have timed out",true);
- }catch (TimeoutException x) {
- assertTrue("Request timed out properly",true);
- }catch (Exception x) {
- assertTrue("Request threw an error",false);
- x.printStackTrace();
- }
- assertEquals(future.get(),item);
- }
-
- protected class OfferThread extends Thread {
- Object item = null;
- long delay = 5000;
- volatile boolean offered = false;
- public OfferThread(Object i, long d) {
- this.item = i;
- this.delay = d;
- this.setDaemon(false);
- this.setName(TestAsyncQueue.class.getName()+"-OfferThread");
- }
- @Override
- public void run() {
- try {
- sleep(delay);
- }catch (Exception ignore){}
- offered = true;
- TestAsyncQueue.this.queue.offer(item);
- }
- }
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.tomcat.jdbc.pool.DataSource;
-import org.apache.tomcat.jdbc.test.driver.Driver;
-
-public class TestConcurrency extends DefaultTestCase {
-
- public static final boolean debug = Boolean.getBoolean("jdbc.debug");
-
- protected volatile DataSource ds = null;
-
- public TestConcurrency(String name) {
- super(name);
- }
-
- @Override
- public void setUp() {
- // TODO Auto-generated method stub
- ds = createDefaultDataSource();
- ds.getPoolProperties().setDriverClassName(Driver.class.getName());
- ds.getPoolProperties().setUrl(Driver.url);
- ds.getPoolProperties().setInitialSize(0);
- ds.getPoolProperties().setMaxIdle(0);
- ds.getPoolProperties().setMinIdle(0);
- ds.getPoolProperties().setMaxActive(10);
- ds.getPoolProperties().setRemoveAbandoned(true);
- ds.getPoolProperties().setLogAbandoned(true);
- ds.getPoolProperties().setTestWhileIdle(true);
- ds.getPoolProperties().setMinEvictableIdleTimeMillis(750);
- ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(25);
- ds.setFairQueue(true);
- }
-
- @Override
- protected void tearDown() throws Exception {
- ds.close(true);
- Driver.reset();
- super.tearDown();
- }
-
- public void testSimple() throws Exception {
- ds.getConnection().close();
- final int iter = 1000 * 10;
- final AtomicInteger loopcount = new AtomicInteger(0);
- final Runnable run = new Runnable() {
- public void run() {
- try {
- while (loopcount.incrementAndGet() < iter) {
- Connection con = ds.getConnection();
- Thread.sleep(10);
- con.close();
- }
- }catch (Exception x) {
- loopcount.set(iter); //stops the test
- x.printStackTrace();
- }
- }
- };
- Thread[] threads = new Thread[20];
- for (int i=0; i<threads.length; i++) {
- threads[i] = new Thread(run);
- }
- for (int i=0; i<threads.length; i++) {
- threads[i].start();
- }
- try {
- while (loopcount.get()<iter) {
- assertTrue("Size comparison(less than 11):",ds.getPool().getSize()<=10);
- if (debug) {
- System.out.println("Size: "+ds.getPool().getSize());
- System.out.println("Used: "+ds.getPool().getActive());
- System.out.println("Idle: "+ds.getPool().getIdle());
- System.out.println("Wait: "+ds.getPool().getWaitCount());
- }
- Thread.sleep(250);
- }
- }catch (Exception x) {
- loopcount.set(iter); //stops the test
- x.printStackTrace();
- }
- for (int i=0; i<threads.length; i++) {
- threads[i].join();
- }
- assertEquals("Size comparison:",10, ds.getPool().getSize());
- assertEquals("Idle comparison:",10, ds.getPool().getIdle());
- assertEquals("Used comparison:",0, ds.getPool().getActive());
- assertEquals("Connect count",10,Driver.connectCount.get());
-
- }
-
- public void testBrutal() throws Exception {
- ds.getPoolProperties().setRemoveAbandoned(false);
- ds.getPoolProperties().setRemoveAbandonedTimeout(1);
- ds.getPoolProperties().setMinEvictableIdleTimeMillis(100);
- ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(10);
- ds.getConnection().close();
- final int iter = 100000 * 10;
- final AtomicInteger loopcount = new AtomicInteger(0);
- final Runnable run = new Runnable() {
- public void run() {
- try {
- while (loopcount.incrementAndGet() < iter) {
- Connection con = ds.getConnection();
- con.close();
- }
- }catch (Exception x) {
- loopcount.set(iter); //stops the test
- x.printStackTrace();
- }
- }
- };
- Thread[] threads = new Thread[20];
- for (int i=0; i<threads.length; i++) {
- threads[i] = new Thread(run);
- }
- for (int i=0; i<threads.length; i++) {
- threads[i].start();
- }
- try {
- while (loopcount.get()<iter) {
- assertTrue("Size comparison(less than 11):",ds.getPool().getSize()<=10);
- ds.getPool().testAllIdle();
- ds.getPool().checkAbandoned();
- ds.getPool().checkIdle();
- }
- }catch (Exception x) {
- loopcount.set(iter); //stops the test
- x.printStackTrace();
- }
- for (int i=0; i<threads.length; i++) {
- threads[i].join();
- }
- System.out.println("Connect count:"+Driver.connectCount.get());
- System.out.println("DisConnect count:"+Driver.disconnectCount.get());
- assertEquals("Size comparison:",10, ds.getPool().getSize());
- assertEquals("Idle comparison:",10, ds.getPool().getIdle());
- assertEquals("Used comparison:",0, ds.getPool().getActive());
- assertEquals("Connect count",10,Driver.connectCount.get());
- }
-
- public void testBrutalNonFair() throws Exception {
- ds.getPoolProperties().setRemoveAbandoned(false);
- ds.getPoolProperties().setRemoveAbandonedTimeout(1);
- ds.getPoolProperties().setMinEvictableIdleTimeMillis(100);
- ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(10);
- ds.getConnection().close();
- final int iter = 100000 * 10;
- final AtomicInteger loopcount = new AtomicInteger(0);
- final Runnable run = new Runnable() {
- public void run() {
- try {
- while (loopcount.incrementAndGet() < iter) {
- Connection con = ds.getConnection();
- con.close();
- }
- }catch (Exception x) {
- loopcount.set(iter); //stops the test
- x.printStackTrace();
- }
- }
- };
- Thread[] threads = new Thread[20];
- for (int i=0; i<threads.length; i++) {
- threads[i] = new Thread(run);
- }
- for (int i=0; i<threads.length; i++) {
- threads[i].start();
- }
- try {
- while (loopcount.get()<iter) {
- assertTrue("Size comparison(less than 11):",ds.getPool().getSize()<=10);
- ds.getPool().testAllIdle();
- ds.getPool().checkAbandoned();
- ds.getPool().checkIdle();
- }
- }catch (Exception x) {
- loopcount.set(iter); //stops the test
- x.printStackTrace();
- }
- for (int i=0; i<threads.length; i++) {
- threads[i].join();
- }
- System.out.println("Connect count:"+Driver.connectCount.get());
- System.out.println("DisConnect count:"+Driver.disconnectCount.get());
- assertEquals("Size comparison:",10, ds.getPool().getSize());
- assertEquals("Idle comparison:",10, ds.getPool().getIdle());
- assertEquals("Used comparison:",0, ds.getPool().getActive());
- assertEquals("Connect count",10,Driver.connectCount.get());
- }
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-
-import org.apache.tomcat.jdbc.pool.DataSourceProxy;
-import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
-
-public class TestConnectionState extends DefaultTestCase {
-
- public TestConnectionState(String name) {
- super(name);
- }
-
- public void testAutoCommitFalse() throws Exception {
- DataSourceProxy d1 = this.createDefaultDataSource();
- d1.setMaxActive(1);
- d1.setMinIdle(1);
- d1.setMaxIdle(1);
- d1.setJdbcInterceptors(ConnectionState.class.getName());
- d1.setDefaultAutoCommit(Boolean.FALSE);
- Connection c1 = d1.getConnection();
- assertFalse("Auto commit should be false",c1.getAutoCommit());
- c1.setAutoCommit(true);
- assertTrue("Auto commit should be true",c1.getAutoCommit());
- c1.close();
- c1 = d1.getConnection();
- assertFalse("Auto commit should be false for a reused connection",c1.getAutoCommit());
- d1.close(true);
- assertTrue("Connection should be closed",c1.isClosed());
- }
-
- public void testAutoCommitTrue() throws Exception {
- DataSourceProxy d1 = this.createDefaultDataSource();
- d1.setMaxActive(1);
- d1.setJdbcInterceptors(ConnectionState.class.getName());
- d1.setDefaultAutoCommit(Boolean.TRUE);
- d1.setMinIdle(1);
- Connection c1 = d1.getConnection();
- assertTrue("Auto commit should be true",c1.getAutoCommit());
- c1.setAutoCommit(false);
- assertFalse("Auto commit should be false",c1.getAutoCommit());
- c1.close();
- c1 = d1.getConnection();
- assertTrue("Auto commit should be true for a reused connection",c1.getAutoCommit());
- }
-
- public void testDefaultCatalog() throws Exception {
- DataSourceProxy d1 = this.createDefaultDataSource();
- d1.setMaxActive(1);
- d1.setJdbcInterceptors(ConnectionState.class.getName());
- d1.setDefaultCatalog("information_schema");
- d1.setMinIdle(1);
- Connection c1 = d1.getConnection();
- assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
- c1.close();
- c1 = d1.getConnection();
- assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
- c1.setCatalog("mysql");
- assertEquals("Catalog should be information_schema",c1.getCatalog(),"mysql");
- c1.close();
- c1 = d1.getConnection();
- assertEquals("Catalog should be information_schema",c1.getCatalog(),"information_schema");
- }
-
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-
-public class TestException extends DefaultTestCase {
-
- public TestException(String name) {
- super(name);
- }
-
- public void testException() throws Exception {
- init();
- datasource.getPoolProperties().setJdbcInterceptors(TestInterceptor.class.getName());
- Connection con = datasource.getConnection();
- try {
- con.createStatement();
- }catch (Exception x) {
-
- }
- }
-
-
- public static class TestInterceptor extends JdbcInterceptor {
-
- @Override
- public void reset(ConnectionPool parent, PooledConnection con) {
- // TODO Auto-generated method stub
-
- }
-
-
- }
-
-}
+++ /dev/null
-/*
- * 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(20000);
- }
-
- public void testClose() throws Exception {
- init();
- datasource.getConnection();
- System.out.println("Got a connection, but didn't return it");
- datasource.close(true);
- Thread.sleep(20000);
- }
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-
-import javax.sql.PooledConnection;
-
-public class TestGetConnection extends DefaultTestCase {
-
- public TestGetConnection(String name) {
- super(name);
- }
-
- public void testGetConnection() throws Exception {
- this.init();
- Connection con = this.datasource.getConnection();
- assertTrue("Connection should implement javax.sql.PooledConnection",con instanceof PooledConnection);
- Connection actual = ((PooledConnection)con).getConnection();
- assertNotNull("Connection delegate should not be null.",actual);
- System.out.println("Actual connection:"+actual.getClass().getName());
-
- }
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-
-import org.apache.tomcat.jdbc.pool.interceptor.TestInterceptor;
-
-public class TestInterceptorShortName extends DefaultTestCase {
-
- public TestInterceptorShortName(String name) {
- super(name);
- }
-
- public void testShortInterceptor() throws Exception {
- this.datasource = this.createDefaultDataSource();
- this.datasource.setJdbcInterceptors("TestInterceptor");
- this.datasource.setMaxActive(1);
- Connection con = this.datasource.getConnection();
- assertTrue("Pool should have been started.",TestInterceptor.poolstarted);
- assertEquals("Only one interceptor should have been called setProperties",1,TestInterceptor.instancecount.get());
- con.close();
- this.datasource.close();
- assertTrue("Pool should have been closed.",TestInterceptor.poolclosed);
- }
-
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import junit.framework.TestCase;
-
-import org.apache.tomcat.jdbc.pool.DataSource;
-import org.apache.tomcat.jdbc.pool.PoolConfiguration;
-import org.apache.tomcat.jdbc.test.driver.Driver;
-/**
- *
- * @author Jeremy Norris
- * https://issues.apache.org/bugzilla/show_bug.cgi?id=50613
- *
- */
-public class TestSizePreservation extends TestCase {
-
- protected volatile DataSource ds = null;
-
- public TestSizePreservation() {
- }
-
- private void initSimplePoolProperties() {
- PoolConfiguration p = new DefaultProperties();
- ds = new org.apache.tomcat.jdbc.pool.DataSource();
- ds.setPoolProperties(p);
-
- ds.getPoolProperties().setDriverClassName(Driver.class.getName());
- ds.getPoolProperties().setUrl(Driver.url);
- ds.getPoolProperties().setFairQueue(true);
- ds.getPoolProperties().setJmxEnabled(false);
- ds.getPoolProperties().setTestWhileIdle(true);
- ds.getPoolProperties().setTestOnBorrow(false);
- ds.getPoolProperties().setTestOnReturn(false);
- ds.getPoolProperties().setValidationInterval(30000);
- ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(30000);
- ds.getPoolProperties().setInitialSize(100);
- ds.getPoolProperties().setMaxActive(100);
- ds.getPoolProperties().setMinIdle(0);
- ds.getPoolProperties().setMaxIdle(0);
- ds.getPoolProperties().setMaxWait(10000);
- ds.getPoolProperties().setRemoveAbandonedTimeout(10);
- ds.getPoolProperties().setMinEvictableIdleTimeMillis(10000);
- ds.getPoolProperties().setLogAbandoned(false);
- ds.getPoolProperties().setRemoveAbandoned(false);
- ds.getPoolProperties().setUseLock(true);
- }
-
- private void initEvictingPool() {
- initSimplePoolProperties();
- ds.getPoolProperties().setTimeBetweenEvictionRunsMillis(25);
- ds.getPoolProperties().setMinEvictableIdleTimeMillis(750);
- ds.getPoolProperties().setRemoveAbandoned(true);
- ds.getPoolProperties().setRemoveAbandonedTimeout(1);
- }
-
- public void testSimple() throws Exception {
- initSimplePoolProperties();
- common();
- ds.close(true);
- Driver.reset();
- }
-
- public void testEvicting() throws Exception {
- initEvictingPool();
- common();
- ds.close(true);
- Driver.reset();
- }
-
- private void common() throws Exception {
- ds.getConnection().close();
- final int iterations = 1000;
- final AtomicInteger loopcount = new AtomicInteger(0);
- final Runnable run = new Runnable() {
- public void run() {
- try {
- while (loopcount.incrementAndGet() < iterations) {
- Connection c = ds.getConnection();
- Thread.sleep(1000);
- c.close();
- }
- } catch (Exception x) {
- x.printStackTrace();
- }
- }
- };
- Thread[] threads = new Thread[200];
- for (int i = 0; i < threads.length; i++) {
- threads[i] = new Thread(run);
- }
- for (int i = 0; i < threads.length; i++) {
- threads[i].start();
- }
- try {
- while (loopcount.get() < iterations) {
- Thread.sleep(250);
- }
- } catch (Exception x) {
- loopcount.set(iterations); // stops the test
- x.printStackTrace();
- }
- for (int i = 0; i < threads.length; i++) {
- threads[i].join();
- }
- System.out.println("Pool size:"+ds.getPool().getSize());
- assertTrue("Size validity check: ", ds.getPool().getSize() >= 0);
- }
-
-}
+++ /dev/null
-/*
- * 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.management.ManagementFactory;
-import java.sql.CallableStatement;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.Statement;
-import java.util.Map;
-
-import javax.management.AttributeChangeNotification;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport;
-import org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx;
-
-public class TestSlowQueryReport extends DefaultTestCase {
-
- public TestSlowQueryReport(String name) {
- super(name);
- }
-
- public void testSlowSql() throws Exception {
- int count = 3;
- this.init();
- this.datasource.setMaxActive(1);
- this.datasource.setJdbcInterceptors(SlowQueryReport.class.getName()+"(threshold=50)");
- Connection con = this.datasource.getConnection();
- String slowSql = "select count(1) from test where val1 like 'ewq%eq' and val2 = 'ew%rre' and val3 = 'sda%da' and val4 = 'dad%ada'";
- for (int i=0; i<count; i++) {
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery(slowSql);
- rs.close();
- st.close();
- }
- Map<String,SlowQueryReport.QueryStats> map = SlowQueryReport.getPoolStats(datasource.getPool().getName());
- assertNotNull(map);
- assertEquals(1,map.size());
- String key = map.keySet().iterator().next();
- SlowQueryReport.QueryStats stats = map.get(key);
- System.out.println("Stats:"+stats);
-
- for (int i=0; i<count; i++) {
- PreparedStatement st = con.prepareStatement(slowSql);
- ResultSet rs = st.executeQuery();
- rs.close();
- st.close();
- }
- System.out.println("Stats:"+stats);
-
- for (int i=0; i<count; i++) {
- CallableStatement st = con.prepareCall(slowSql);
- ResultSet rs = st.executeQuery();
- rs.close();
- st.close();
- }
- System.out.println("Stats:"+stats);
- ConnectionPool pool = datasource.getPool();
- con.close();
- tearDown();
- //make sure we actually did clean up when the pool closed
- assertNull(SlowQueryReport.getPoolStats(pool.getName()));
- }
-
- public void testSlowSqlJmx() throws Exception {
- int count = 1;
- this.init();
- this.datasource.setMaxActive(1);
- this.datasource.setJdbcInterceptors(SlowQueryReportJmx.class.getName()+"(threshold=50,notifyPool=false)");
- Connection con = this.datasource.getConnection();
- String slowSql = "select count(1) from test where val1 like 'ewq%eq'";
- for (int i=0; i<count; i++) {
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery(slowSql);
- rs.close();
- st.close();
- }
- Map<String,SlowQueryReport.QueryStats> map = SlowQueryReport.getPoolStats(datasource.getPool().getName());
- assertNotNull(map);
- assertEquals(1,map.size());
- String key = map.keySet().iterator().next();
- SlowQueryReport.QueryStats stats = map.get(key);
- System.out.println("Stats:"+stats);
- ClientListener listener = new ClientListener();
- ConnectionPool pool = datasource.getPool();
- ManagementFactory.getPlatformMBeanServer().addNotificationListener(
- SlowQueryReportJmx.getObjectName(SlowQueryReportJmx.class, pool.getName()),
- listener,
- null,
- null);
-
- for (int i=0; i<count; i++) {
- PreparedStatement st = con.prepareStatement(slowSql);
- ResultSet rs = st.executeQuery();
- rs.close();
- st.close();
- }
- System.out.println("Stats:"+stats);
-
- for (int i=0; i<count; i++) {
- CallableStatement st = con.prepareCall(slowSql);
- ResultSet rs = st.executeQuery();
- rs.close();
- st.close();
- }
- System.out.println("Stats:"+stats);
- assertEquals("Expecting to have received "+(2*count)+" notifications.",2*count, listener.notificationCount);
- con.close();
- tearDown();
- //make sure we actually did clean up when the pool closed
- assertNull(SlowQueryReport.getPoolStats(pool.getName()));
- }
-
-
- public void testFastSql() throws Exception {
- int count = 3;
- this.init();
- this.datasource.setMaxActive(1);
- this.datasource.setJdbcInterceptors(SlowQueryReport.class.getName());
- Connection con = this.datasource.getConnection();
- String fastSql = this.datasource.getValidationQuery();
- for (int i=0; i<count; i++) {
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery(fastSql);
- rs.close();
- st.close();
- }
- Map<String,SlowQueryReport.QueryStats> map = SlowQueryReport.getPoolStats(datasource.getPool().getName());
- assertNotNull(map);
- assertEquals(0,map.size());
- ConnectionPool pool = datasource.getPool();
- con.close();
- tearDown();
- assertNull(SlowQueryReport.getPoolStats(pool.getName()));
- }
-
- public void testFailedSql() throws Exception {
- int count = 3;
- this.init();
- this.datasource.setMaxActive(1);
- this.datasource.setJdbcInterceptors(SlowQueryReport.class.getName());
- Connection con = this.datasource.getConnection();
- String slowSql = "select 1 from non_existent";
- int exceptionCount = 0;
- for (int i=0; i<count; i++) {
- Statement st = con.createStatement();
- try {
- ResultSet rs = st.executeQuery(slowSql);
- rs.close();
- }catch (Exception x) {
- exceptionCount++;
- }
- st.close();
-
- }
- Map<String,SlowQueryReport.QueryStats> map = SlowQueryReport.getPoolStats(datasource.getPool().getName());
- assertNotNull(map);
- assertEquals(1,map.size());
- ConnectionPool pool = datasource.getPool();
- String key = map.keySet().iterator().next();
- SlowQueryReport.QueryStats stats = map.get(key);
- System.out.println("Stats:"+stats);
- con.close();
- tearDown();
- assertNull(SlowQueryReport.getPoolStats(pool.getName()));
- }
-
-
- public class ClientListener implements NotificationListener {
- volatile int notificationCount = 0;
- public void handleNotification(Notification notification,
- Object handback) {
- notificationCount++;
- System.out.println("\nReceived notification:");
- System.out.println("\tClassName: " + notification.getClass().getName());
- System.out.println("\tSource: " + notification.getSource());
- System.out.println("\tType: " + notification.getType());
- System.out.println("\tMessage: " + notification.getMessage());
- if (notification instanceof AttributeChangeNotification) {
- AttributeChangeNotification acn =
- (AttributeChangeNotification) notification;
- System.out.println("\tAttributeName: " + acn.getAttributeName());
- System.out.println("\tAttributeType: " + acn.getAttributeType());
- System.out.println("\tNewValue: " + acn.getNewValue());
- System.out.println("\tOldValue: " + acn.getOldValue());
- }
- }
- }
-
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-import java.sql.PreparedStatement;
-
-import org.apache.tomcat.jdbc.pool.interceptor.StatementCache;
-
-public class TestStatementCache extends DefaultTestCase {
-
-
- public TestStatementCache(String name) {
- super(name);
- }
-
- private static volatile TestStatementCacheInterceptor interceptor = null;
-
-
- @Override
- protected void tearDown() throws Exception {
- // TODO Auto-generated method stub
- this.interceptor = null;
- super.tearDown();
- }
-
-
- private void config(boolean cachePrepared, boolean cacheCallable, int max) {
- datasource.getPoolProperties().setJdbcInterceptors(TestStatementCacheInterceptor.class.getName()+
- "(prepared="+cachePrepared+",callable="+cacheCallable+",max="+max+")");
- }
-
- public void testIsCacheEnabled() throws Exception {
- init();
- config(true,true,50);
- datasource.getConnection().close();
- assertNotNull("Interceptor was not created.", interceptor);
- }
-
- public void testCacheProperties() throws Exception {
- init();
- config(true,true,50);
- datasource.getConnection().close();
- assertEquals(true, interceptor.isCacheCallable());
- assertEquals(true, interceptor.isCachePrepared());
- assertEquals(50,interceptor.getMaxCacheSize());
- }
-
- public void testCacheProperties2() throws Exception {
- init();
- config(false,false,100);
- datasource.getConnection().close();
- assertEquals(false, interceptor.isCacheCallable());
- assertEquals(false, interceptor.isCachePrepared());
- assertEquals(100,interceptor.getMaxCacheSize());
- }
-
- public void testPreparedStatementCache() throws Exception {
- init();
- config(true,false,100);
- Connection con = datasource.getConnection();
- PreparedStatement ps1 = con.prepareStatement("select 1");
- PreparedStatement ps2 = con.prepareStatement("select 1");
- assertEquals(0,interceptor.getCacheSize().get());
- ps1.close();
- assertTrue(ps1.isClosed());
- assertEquals(1,interceptor.getCacheSize().get());
- PreparedStatement ps3 = con.prepareStatement("select 1");
- assertEquals(0,interceptor.getCacheSize().get());
- ps2.close();
- assertTrue(ps2.isClosed());
- ps3.close();
- assertTrue(ps3.isClosed());
- assertEquals(1,interceptor.getCacheSize().get());
- }
-
- public void testPreparedStatementCache2() throws Exception {
- init();
- config(false,false,100);
- Connection con = datasource.getConnection();
- PreparedStatement ps1 = con.prepareStatement("select 1");
- PreparedStatement ps2 = con.prepareStatement("select 1");
- assertEquals(0,interceptor.getCacheSize().get());
- ps1.close();
- assertTrue(ps1.isClosed());
- assertEquals(0,interceptor.getCacheSize().get());
- PreparedStatement ps3 = con.prepareStatement("select 1");
- assertEquals(0,interceptor.getCacheSize().get());
- ps2.close();
- assertTrue(ps2.isClosed());
- ps3.close();
- assertTrue(ps3.isClosed());
- assertEquals(0,interceptor.getCacheSize().get());
- }
-
- public void testCallableStatementCache() throws Exception {
- }
-
- public void testMaxCacheSize() throws Exception {
- init();
- config(true,false,100);
- Connection con1 = datasource.getConnection();
- Connection con2 = datasource.getConnection();
- for (int i=0; i<120; i++) {
- Connection con = (i%2==0)?con1:con2;
- PreparedStatement ps = con.prepareStatement("select "+i);
- ps.close();
- }
- assertEquals(100,interceptor.getCacheSize().get());
- }
-
-
- public static class TestStatementCacheInterceptor extends StatementCache {
- public TestStatementCacheInterceptor() {
- TestStatementCache.interceptor = this;
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-
-
-public class TestSuspectTimeout extends DefaultTestCase {
-
- public TestSuspectTimeout(String name) {
- super(name);
- }
-
- public void testSuspect() throws Exception {
- this.init();
- this.datasource.setMaxActive(100);
- this.datasource.setMaxIdle(100);
- this.datasource.setInitialSize(0);
- this.datasource.getPoolProperties().setAbandonWhenPercentageFull(0);
- this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(100);
- this.datasource.getPoolProperties().setRemoveAbandoned(true);
- this.datasource.getPoolProperties().setRemoveAbandonedTimeout(100);
- this.datasource.getPoolProperties().setSuspectTimeout(1);
- this.datasource.getPoolProperties().setLogAbandoned(true);
- Connection con = datasource.getConnection();
- assertEquals("Number of connections active/busy should be 1",1,datasource.getPool().getActive());
- Thread.sleep(3000);
- PooledConnection pcon = con.unwrap(PooledConnection.class);
- assertTrue("Connection should be marked suspect",pcon.isSuspect());
- con.close();
- }
-}
+++ /dev/null
-/*
- * 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(5);
- 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.");
- }
- assertTrue(false);
- } catch ( Exception x ) {
- assertTrue(true);
- }finally {
- Thread.sleep(2000);
- tearDown();
- }
- }
-
- public void testCheckoutTimeoutFair() throws Exception {
- try {
- init();
- this.datasource.getPoolProperties().setFairQueue(true);
- 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(5);
- 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.");
- }
- assertTrue(false);
- } catch ( Exception x ) {
- assertTrue(true);
- }finally {
- Thread.sleep(2000);
- tearDown();
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.sql.Connection;
-
-public class TwoDataSources extends DefaultTestCase {
-
- public TwoDataSources(String name) {
- super(name);
- }
-
- public void testTwoDataSources() throws Exception {
- org.apache.tomcat.jdbc.pool.DataSource d1 = this.createDefaultDataSource();
- org.apache.tomcat.jdbc.pool.DataSource d2 = this.createDefaultDataSource();
- d1.setRemoveAbandoned(true);
- d1.setRemoveAbandonedTimeout(10);
- d1.setTimeBetweenEvictionRunsMillis(1000);
- d2.setRemoveAbandoned(false);
- Connection c1 = d1.getConnection();
- Connection c2 = d2.getConnection();
- Thread.sleep(5000);
- try {
- c1.createStatement();
- assertTrue("Connection should have been abandoned.",false);
- }catch (Exception x) {
- assertTrue("This is correct, c1 is abandoned",true);
- }
-
- try {
- c2.createStatement();
- assertTrue("Connection should not have been abandoned.",true);
- }catch (Exception x) {
- assertTrue("Connection c2 should be working",false);
- }
- try {
- assertTrue("Connection should have been closed.",c1.isClosed());
- }catch (Exception x) {
- assertTrue("This is correct, c1 is closed",true);
- }
- try {
- assertFalse("Connection c2 should not have been closed.",c2.isClosed());
- }catch (Exception x) {
- assertTrue("Connection c2 should be working",false);
- }
-
-
- }
-
-}
+++ /dev/null
-/*
- * 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.driver;
-
-import java.sql.Array;
-import java.sql.Blob;
-import java.sql.CallableStatement;
-import java.sql.Clob;
-import java.sql.DatabaseMetaData;
-import java.sql.NClob;
-import java.sql.PreparedStatement;
-import java.sql.SQLClientInfoException;
-import java.sql.SQLException;
-import java.sql.SQLWarning;
-import java.sql.SQLXML;
-import java.sql.Savepoint;
-import java.sql.Statement;
-import java.sql.Struct;
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.tomcat.jdbc.pool.PooledConnection;
-
-public class Connection implements java.sql.Connection {
- Properties info;
-
- public Connection(Properties info) {
- this.info = info;
- }
-
- public String getUsername() {
- return info.getProperty(PooledConnection.PROP_USER);
- }
-
- public String getPassword() {
- return info.getProperty(PooledConnection.PROP_PASSWORD);
- }
-
- public void clearWarnings() throws SQLException {
- }
-
- public void close() throws SQLException {
- Driver.disconnectCount.incrementAndGet();
- }
-
- public void commit() throws SQLException {
- }
-
- public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
- return null;
- }
-
- public Blob createBlob() throws SQLException {
- return null;
- }
-
- public Clob createClob() throws SQLException {
- return null;
- }
-
- public NClob createNClob() throws SQLException {
- return null;
- }
-
- public SQLXML createSQLXML() throws SQLException {
- return null;
- }
-
- public Statement createStatement() throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
- return null;
- }
-
- public boolean getAutoCommit() throws SQLException {
- return false;
- }
-
- public String getCatalog() throws SQLException {
- return null;
- }
-
- public Properties getClientInfo() throws SQLException {
- return null;
- }
-
- public String getClientInfo(String name) throws SQLException {
- return null;
- }
-
- public int getHoldability() throws SQLException {
- return 0;
- }
-
- public DatabaseMetaData getMetaData() throws SQLException {
- return null;
- }
-
- public int getTransactionIsolation() throws SQLException {
- return 0;
- }
-
- public Map<String, Class<?>> getTypeMap() throws SQLException {
- return null;
- }
-
- public SQLWarning getWarnings() throws SQLException {
- return null;
- }
-
- public boolean isClosed() throws SQLException {
- return false;
- }
-
- public boolean isReadOnly() throws SQLException {
- return false;
- }
-
- public boolean isValid(int timeout) throws SQLException {
- return false;
- }
-
- public String nativeSQL(String sql) throws SQLException {
- return null;
- }
-
- public CallableStatement prepareCall(String sql) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public PreparedStatement prepareStatement(String sql) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
-
- public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
-
- public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
- return new org.apache.tomcat.jdbc.test.driver.Statement();
- }
-
- public void releaseSavepoint(Savepoint savepoint) throws SQLException {
- }
-
- public void rollback() throws SQLException {
- }
-
- public void rollback(Savepoint savepoint) throws SQLException {
- }
-
- public void setAutoCommit(boolean autoCommit) throws SQLException {
- }
-
- public void setCatalog(String catalog) throws SQLException {
- }
-
- public void setClientInfo(Properties properties) throws SQLClientInfoException {
- }
-
- public void setClientInfo(String name, String value) throws SQLClientInfoException {
- }
-
- public void setHoldability(int holdability) throws SQLException {
- }
-
- public void setReadOnly(boolean readOnly) throws SQLException {
- }
-
- public Savepoint setSavepoint() throws SQLException {
- return null;
- }
-
- public Savepoint setSavepoint(String name) throws SQLException {
- return null;
- }
-
- public void setTransactionIsolation(int level) throws SQLException {
- }
-
- public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
- }
-
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- return false;
- }
-
- public <T> T unwrap(Class<T> iface) throws SQLException {
- return null;
- }
-
-}
+++ /dev/null
-/*
- * 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.driver;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.DriverPropertyInfo;
-import java.sql.SQLException;
-import java.util.Properties;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class Driver implements java.sql.Driver {
- public static final String url = "jdbc:tomcat:test";
- public static final AtomicInteger connectCount = new AtomicInteger(0);
- public static final AtomicInteger disconnectCount = new AtomicInteger(0);
-
- public static void reset() {
- connectCount.set(0);
- disconnectCount.set(0);
- }
-
- static {
- try {
- DriverManager.registerDriver(new Driver());
- }catch (Exception x) {
- x.printStackTrace();
- throw new RuntimeException(x);
- }
- }
-
- public Driver() {
- }
-
- public boolean acceptsURL(String url) throws SQLException {
- return url!=null && url.equals(Driver.url);
- }
-
- public Connection connect(String url, Properties info) throws SQLException {
- connectCount.addAndGet(1);
- return new org.apache.tomcat.jdbc.test.driver.Connection(info);
- }
-
- public int getMajorVersion() {
- return 0;
- }
-
- public int getMinorVersion() {
- return 0;
- }
-
- public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
- return null;
- }
-
- public boolean jdbcCompliant() {
- return false;
- }
-}
+++ /dev/null
-/*
- * 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.driver;
-
-import java.io.InputStream;
-import java.io.Reader;
-import java.math.BigDecimal;
-import java.net.URL;
-import java.sql.Array;
-import java.sql.Blob;
-import java.sql.Clob;
-import java.sql.Date;
-import java.sql.NClob;
-import java.sql.Ref;
-import java.sql.ResultSetMetaData;
-import java.sql.RowId;
-import java.sql.SQLException;
-import java.sql.SQLWarning;
-import java.sql.SQLXML;
-import java.sql.Statement;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.util.Calendar;
-import java.util.Map;
-
-public class ResultSet implements java.sql.ResultSet {
- boolean hasNext = true;
-
- public boolean absolute(int row) throws SQLException {
- return false;
- }
-
- public void afterLast() throws SQLException {
- }
-
- public void beforeFirst() throws SQLException {
- }
-
- public void cancelRowUpdates() throws SQLException {
- }
-
- public void clearWarnings() throws SQLException {
- }
- public void close() throws SQLException {
- }
-
- public void deleteRow() throws SQLException {
- }
-
- public int findColumn(String columnLabel) throws SQLException {
- return 0;
- }
-
- public boolean first() throws SQLException {
- return hasNext;
- }
-
- public Array getArray(int columnIndex) throws SQLException {
- return null;
- }
-
- public Array getArray(String columnLabel) throws SQLException {
- return null;
- }
-
- @Override
- public InputStream getAsciiStream(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public InputStream getAsciiStream(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public BigDecimal getBigDecimal(int columnIndex, int scale)
- throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public BigDecimal getBigDecimal(String columnLabel, int scale)
- throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public InputStream getBinaryStream(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public InputStream getBinaryStream(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Blob getBlob(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Blob getBlob(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public boolean getBoolean(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean getBoolean(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public byte getByte(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public byte getByte(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public byte[] getBytes(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public byte[] getBytes(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Reader getCharacterStream(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Reader getCharacterStream(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Clob getClob(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Clob getClob(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int getConcurrency() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public String getCursorName() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Date getDate(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Date getDate(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Date getDate(int columnIndex, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Date getDate(String columnLabel, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public double getDouble(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public double getDouble(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getFetchDirection() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getFetchSize() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public float getFloat(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public float getFloat(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getHoldability() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getInt(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getInt(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public long getLong(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public long getLong(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public ResultSetMetaData getMetaData() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Reader getNCharacterStream(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Reader getNCharacterStream(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public NClob getNClob(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public NClob getNClob(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public String getNString(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public String getNString(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object getObject(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object getObject(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object getObject(int columnIndex, Map<String, Class<?>> map)
- throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object getObject(String columnLabel, Map<String, Class<?>> map)
- throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Ref getRef(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Ref getRef(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int getRow() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public RowId getRowId(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public RowId getRowId(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SQLXML getSQLXML(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SQLXML getSQLXML(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public short getShort(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public short getShort(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public Statement getStatement() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public String getString(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public String getString(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Time getTime(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Time getTime(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Time getTime(int columnIndex, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Time getTime(String columnLabel, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Timestamp getTimestamp(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Timestamp getTimestamp(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Timestamp getTimestamp(int columnIndex, Calendar cal)
- throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Timestamp getTimestamp(String columnLabel, Calendar cal)
- throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int getType() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public URL getURL(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public URL getURL(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public InputStream getUnicodeStream(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public InputStream getUnicodeStream(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SQLWarning getWarnings() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void insertRow() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean isAfterLast() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean isBeforeFirst() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean isClosed() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean isFirst() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean isLast() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean last() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void moveToCurrentRow() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void moveToInsertRow() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean next() throws SQLException {
- boolean next = hasNext;
- hasNext = false;
- // TODO Auto-generated method stub
- return next;
- }
-
- @Override
- public boolean previous() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void refreshRow() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean relative(int rows) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean rowDeleted() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean rowInserted() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean rowUpdated() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void setFetchDirection(int direction) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setFetchSize(int rows) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateArray(int columnIndex, Array x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateArray(String columnLabel, Array x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateAsciiStream(int columnIndex, InputStream x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateAsciiStream(String columnLabel, InputStream x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateAsciiStream(int columnIndex, InputStream x, int length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateAsciiStream(String columnLabel, InputStream x, int length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateAsciiStream(int columnIndex, InputStream x, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateAsciiStream(String columnLabel, InputStream x, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBigDecimal(int columnIndex, BigDecimal x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBigDecimal(String columnLabel, BigDecimal x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBinaryStream(int columnIndex, InputStream x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBinaryStream(String columnLabel, InputStream x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBinaryStream(int columnIndex, InputStream x, int length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBinaryStream(String columnLabel, InputStream x, int length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBinaryStream(int columnIndex, InputStream x, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBinaryStream(String columnLabel, InputStream x,
- long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBlob(int columnIndex, Blob x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBlob(String columnLabel, Blob x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBlob(int columnIndex, InputStream inputStream)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBlob(String columnLabel, InputStream inputStream)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBlob(int columnIndex, InputStream inputStream, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBlob(String columnLabel, InputStream inputStream,
- long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBoolean(int columnIndex, boolean x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBoolean(String columnLabel, boolean x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateByte(int columnIndex, byte x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateByte(String columnLabel, byte x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBytes(int columnIndex, byte[] x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateBytes(String columnLabel, byte[] x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateCharacterStream(int columnIndex, Reader x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateCharacterStream(String columnLabel, Reader reader)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateCharacterStream(int columnIndex, Reader x, int length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateCharacterStream(String columnLabel, Reader reader,
- int length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateCharacterStream(int columnIndex, Reader x, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateCharacterStream(String columnLabel, Reader reader,
- long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateClob(int columnIndex, Clob x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateClob(String columnLabel, Clob x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateClob(int columnIndex, Reader reader) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateClob(String columnLabel, Reader reader)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateClob(int columnIndex, Reader reader, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateClob(String columnLabel, Reader reader, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateDate(int columnIndex, Date x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateDate(String columnLabel, Date x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateDouble(int columnIndex, double x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateDouble(String columnLabel, double x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateFloat(int columnIndex, float x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateFloat(String columnLabel, float x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateInt(int columnIndex, int x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateInt(String columnLabel, int x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateLong(int columnIndex, long x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateLong(String columnLabel, long x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNCharacterStream(int columnIndex, Reader x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNCharacterStream(String columnLabel, Reader reader)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNCharacterStream(int columnIndex, Reader x, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNCharacterStream(String columnLabel, Reader reader,
- long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNClob(int columnIndex, NClob clob) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNClob(String columnLabel, NClob clob) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNClob(int columnIndex, Reader reader) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNClob(String columnLabel, Reader reader)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNClob(int columnIndex, Reader reader, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNClob(String columnLabel, Reader reader, long length)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNString(int columnIndex, String string)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNString(String columnLabel, String string)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNull(int columnIndex) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateNull(String columnLabel) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateObject(int columnIndex, Object x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateObject(String columnLabel, Object x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateObject(int columnIndex, Object x, int scaleOrLength)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateObject(String columnLabel, Object x, int scaleOrLength)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateRef(int columnIndex, Ref x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateRef(String columnLabel, Ref x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateRow() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateRowId(int columnIndex, RowId x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateRowId(String columnLabel, RowId x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateSQLXML(int columnIndex, SQLXML xmlObject)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateSQLXML(String columnLabel, SQLXML xmlObject)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateShort(int columnIndex, short x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateShort(String columnLabel, short x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateString(int columnIndex, String x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateString(String columnLabel, String x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateTime(int columnIndex, Time x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateTime(String columnLabel, Time x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateTimestamp(int columnIndex, Timestamp x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void updateTimestamp(String columnLabel, Timestamp x)
- throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean wasNull() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public <T> T unwrap(Class<T> iface) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
-}
+++ /dev/null
-/*
- * 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.driver;
-
-import java.io.InputStream;
-import java.io.Reader;
-import java.math.BigDecimal;
-import java.net.URL;
-import java.sql.Array;
-import java.sql.Blob;
-import java.sql.CallableStatement;
-import java.sql.Clob;
-import java.sql.Connection;
-import java.sql.Date;
-import java.sql.NClob;
-import java.sql.ParameterMetaData;
-import java.sql.Ref;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.RowId;
-import java.sql.SQLException;
-import java.sql.SQLWarning;
-import java.sql.SQLXML;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.util.Calendar;
-import java.util.Map;
-
-public class Statement implements CallableStatement {
-
- @Override
- public Array getArray(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Array getArray(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public BigDecimal getBigDecimal(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public BigDecimal getBigDecimal(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Blob getBlob(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Blob getBlob(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public boolean getBoolean(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean getBoolean(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public byte getByte(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public byte getByte(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public byte[] getBytes(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public byte[] getBytes(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Reader getCharacterStream(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Reader getCharacterStream(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Clob getClob(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Clob getClob(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Date getDate(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Date getDate(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Date getDate(int parameterIndex, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Date getDate(String parameterName, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public double getDouble(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public double getDouble(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public float getFloat(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public float getFloat(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getInt(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getInt(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public long getLong(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public long getLong(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public Reader getNCharacterStream(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Reader getNCharacterStream(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public NClob getNClob(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public NClob getNClob(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public String getNString(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public String getNString(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object getObject(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object getObject(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object getObject(int parameterIndex, Map<String, Class<?>> map) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Object getObject(String parameterName, Map<String, Class<?>> map) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Ref getRef(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Ref getRef(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public RowId getRowId(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public RowId getRowId(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SQLXML getSQLXML(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SQLXML getSQLXML(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public short getShort(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public short getShort(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public String getString(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public String getString(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Time getTime(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Time getTime(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Time getTime(int parameterIndex, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Time getTime(String parameterName, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Timestamp getTimestamp(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Timestamp getTimestamp(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Timestamp getTimestamp(int parameterIndex, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Timestamp getTimestamp(String parameterName, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public URL getURL(int parameterIndex) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public URL getURL(String parameterName) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void registerOutParameter(String parameterName, int sqlType) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void registerOutParameter(int parameterIndex, int sqlType, int scale) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void registerOutParameter(String parameterName, int sqlType, int scale) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void registerOutParameter(String parameterName, int sqlType, String typeName) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setAsciiStream(String parameterName, InputStream x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setAsciiStream(String parameterName, InputStream x, int length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setAsciiStream(String parameterName, InputStream x, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBigDecimal(String parameterName, BigDecimal x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBinaryStream(String parameterName, InputStream x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBinaryStream(String parameterName, InputStream x, int length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBinaryStream(String parameterName, InputStream x, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBlob(String parameterName, Blob x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBlob(String parameterName, InputStream inputStream) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBoolean(String parameterName, boolean x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setByte(String parameterName, byte x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBytes(String parameterName, byte[] x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setCharacterStream(String parameterName, Reader reader) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setCharacterStream(String parameterName, Reader reader, int length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setClob(String parameterName, Clob x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setClob(String parameterName, Reader reader) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setClob(String parameterName, Reader reader, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setDate(String parameterName, Date x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setDate(String parameterName, Date x, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setDouble(String parameterName, double x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setFloat(String parameterName, float x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setInt(String parameterName, int x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setLong(String parameterName, long x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNCharacterStream(String parameterName, Reader value) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNClob(String parameterName, NClob value) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNClob(String parameterName, Reader reader) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNClob(String parameterName, Reader reader, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNString(String parameterName, String value) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNull(String parameterName, int sqlType) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNull(String parameterName, int sqlType, String typeName) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setObject(String parameterName, Object x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setObject(String parameterName, Object x, int targetSqlType) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setObject(String parameterName, Object x, int targetSqlType, int scale) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setRowId(String parameterName, RowId x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setShort(String parameterName, short x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setString(String parameterName, String x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setTime(String parameterName, Time x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setTime(String parameterName, Time x, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setTimestamp(String parameterName, Timestamp x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setTimestamp(String parameterName, Timestamp x, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setURL(String parameterName, URL val) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean wasNull() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void addBatch() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void clearParameters() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean execute() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public ResultSet executeQuery() throws SQLException {
- // TODO Auto-generated method stub
- return new org.apache.tomcat.jdbc.test.driver.ResultSet();
- }
-
- @Override
- public int executeUpdate() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public ResultSetMetaData getMetaData() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public ParameterMetaData getParameterMetaData() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void setArray(int parameterIndex, Array x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBlob(int parameterIndex, Blob x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBoolean(int parameterIndex, boolean x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setByte(int parameterIndex, byte x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setBytes(int parameterIndex, byte[] x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setClob(int parameterIndex, Clob x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setClob(int parameterIndex, Reader reader) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setDate(int parameterIndex, Date x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setDouble(int parameterIndex, double x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setFloat(int parameterIndex, float x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setInt(int parameterIndex, int x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setLong(int parameterIndex, long x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNClob(int parameterIndex, NClob value) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNClob(int parameterIndex, Reader reader) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNString(int parameterIndex, String value) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNull(int parameterIndex, int sqlType) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setObject(int parameterIndex, Object x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setRef(int parameterIndex, Ref x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setRowId(int parameterIndex, RowId x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setShort(int parameterIndex, short x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setString(int parameterIndex, String x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setTime(int parameterIndex, Time x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setURL(int parameterIndex, URL x) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void addBatch(String sql) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void cancel() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void clearBatch() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void clearWarnings() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void close() throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean execute(String sql) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean execute(String sql, int[] columnIndexes) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean execute(String sql, String[] columnNames) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public int[] executeBatch() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public ResultSet executeQuery(String sql) throws SQLException {
- // TODO Auto-generated method stub
- return new org.apache.tomcat.jdbc.test.driver.ResultSet();
- }
-
- @Override
- public int executeUpdate(String sql) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int executeUpdate(String sql, String[] columnNames) throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public Connection getConnection() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int getFetchDirection() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getFetchSize() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public ResultSet getGeneratedKeys() throws SQLException {
- // TODO Auto-generated method stub
- return new org.apache.tomcat.jdbc.test.driver.ResultSet();
- }
-
- @Override
- public int getMaxFieldSize() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getMaxRows() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public boolean getMoreResults() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean getMoreResults(int current) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public int getQueryTimeout() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public ResultSet getResultSet() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int getResultSetConcurrency() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getResultSetHoldability() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getResultSetType() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getUpdateCount() throws SQLException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public SQLWarning getWarnings() throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public boolean isClosed() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean isPoolable() throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void setCursorName(String name) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setEscapeProcessing(boolean enable) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setFetchDirection(int direction) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setFetchSize(int rows) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setMaxFieldSize(int max) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setMaxRows(int max) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setPoolable(boolean poolable) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setQueryTimeout(int seconds) throws SQLException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public <T> T unwrap(Class<T> iface) throws SQLException {
- // TODO Auto-generated method stub
- return null;
- }
-
-}