From: fhanik Date: Wed, 30 Mar 2011 21:40:59 +0000 (+0000) Subject: Add in ability to build with Maven X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=156e781facd5a9519206a127ec69595ac5ce0898;p=tomcat7.0 Add in ability to build with Maven git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1087090 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/jdbc-pool/.classpath b/modules/jdbc-pool/.classpath index 180fbc72d..1a23a7e18 100644 --- a/modules/jdbc-pool/.classpath +++ b/modules/jdbc-pool/.classpath @@ -6,6 +6,6 @@ - + diff --git a/modules/jdbc-pool/build.xml b/modules/jdbc-pool/build.xml index 389b91092..6cd65f2c3 100644 --- a/modules/jdbc-pool/build.xml +++ b/modules/jdbc-pool/build.xml @@ -114,7 +114,7 @@ - - + @@ -133,13 +133,13 @@ - + - - + @@ -163,7 +163,7 @@ - + @@ -173,7 +173,7 @@ - - + - + @@ -439,7 +439,7 @@ - + @@ -453,7 +453,7 @@ - + @@ -470,7 +470,7 @@ - + @@ -495,7 +495,7 @@ - + diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java deleted file mode 100644 index 5fd7007c5..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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: - *

- * <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"/>
- * 
- * - */ -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 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); - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java deleted file mode 100644 index 0faccfee6..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - -import java.lang.reflect.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 busy; - - /** - * Contains all the idle connections - */ - private BlockingQueue 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()); - - /** - * 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 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 pcf = ((FairBlockingQueue)idle).pollAsync(); - return new ConnectionFuture(pcf); - } else if (idle instanceof MultiLockFairBlockingQueue) { - Future pcf = ((MultiLockFairBlockingQueue)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 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(properties.getMaxActive(),false); - //busy = new FairBlockingQueue(); - //make space for 10 extra in case we flow over a bit - if (properties.isFairQueue()) { - idle = new FairBlockingQueue(); - //idle = new MultiLockFairBlockingQueue(); - } else { - idle = new ArrayBlockingQueue(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.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() 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 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 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 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, Runnable { - Future 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 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() - * {@inheritDoc} - */ - public void postDeregister() { - if (oname!=null) unregisterJmx(); - } - - /** - * no-op
- * {@inheritDoc} - */ - public void postRegister(Boolean registrationDone) { - // NOOP - } - - - /** - * no-op
- * {@inheritDoc} - */ - public void preDeregister() throws Exception { - // NOOP - } - - /** - * If the connection pool MBean exists, it will be registered during this operation.
- * {@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 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); - } - } - - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java deleted file mode 100644 index 32e5a4ed6..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - - -import java.io.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; - -/** - *

JNDI object factory that creates an instance of - * BasicDataSource that has been configured based on the - * RefAddr values of the specified Reference, - * which must match the names and data types of the - * BasicDataSource bean properties.

- *
- * Properties available for configuration:
- * Commons DBCP properties
- *
    - *
  1. initSQL - A query that gets executed once, right after the connection is established.
  2. - *
  3. testOnConnect - run validationQuery after connection has been established.
  4. - *
  5. validationInterval - avoid excess validation, only run validation at most at this frequency - time in milliseconds.
  6. - *
  7. jdbcInterceptors - a semicolon separated list of classnames extending {@link JdbcInterceptor} class.
  8. - *
  9. jmxEnabled - true of false, whether to register the pool with JMX.
  10. - *
  11. fairQueue - true of false, whether the pool should sacrifice a little bit of performance for true fairness.
  12. - *
- * @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 - - /** - *

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

- * - * @param obj The possibly null object containing location or - * reference information that can be used in creating an object - * @param name The name of this object relative to nameCtx - * @param nameCtx The context relative to which the name - * parameter is specified, or null if name - * is relative to the default initial context - * @param environment The possibly null environment that is used in - * creating this object - * - * @exception Exception if an exception occurs creating the instance - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) throws Exception { - - // We only know how to deal with javax.naming.References - // that specify a class name of "javax.sql.DataSource" - if ((obj == null) || !(obj instanceof Reference)) { - return null; - } - Reference ref = (Reference) obj; - 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); - } - } - - /** - *

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

- * @param propText - * @return Properties - * @throws Exception - */ - static protected Properties getProperties(String propText) throws IOException { - return PoolProperties.getProperties(propText,null); - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java deleted file mode 100644 index e8399913e..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java +++ /dev/null @@ -1,1084 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - -import java.io.PrintWriter; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Iterator; -import 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. - *
- * 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 unwrap(Class 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 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); - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java deleted file mode 100644 index ea56e8671..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - -import java.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. - *
- * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented. - * @author Filip Hanik - * - */ - -public class FairBlockingQueue implements BlockingQueue { - - /** - * 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 items; - - /** - * All threads waiting for an object are stored in a linked list - */ - final LinkedList> waiters; - - /** - * Creates a new fair blocking queue. - */ - public FairBlockingQueue() { - items = new LinkedList(); - waiters = new LinkedList>(); - } - - //------------------------------------------------------------------ - // 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 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 c = new ExchangeCountDownLatch(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 pollAsync() { - Future 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 c = new ExchangeCountDownLatch(1); - waiters.addLast(c); - lock.unlock(); - //return a future that will wait for the object - result = new ItemFuture(c); - } else { - lock.unlock(); - //return a future with the item - result = new ItemFuture(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 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 c, int maxElements) { - throw new UnsupportedOperationException("int drainTo(Collection c, int maxElements)"); - } - - /** - * {@inheritDoc} - * @throws UnsupportedOperationException - this operation is not supported - */ - - public int drainTo(Collection 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 c) { - Iterator 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[] toArray(T[] a) { - throw new UnsupportedOperationException(" 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 implements Future { - protected volatile T item = null; - protected volatile ExchangeCountDownLatch latch = null; - protected volatile boolean canceled = false; - - public ItemFuture(T item) { - this.item = item; - } - - public ItemFuture(ExchangeCountDownLatch 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 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[] 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 - * 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 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 false 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. - *
- * 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 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 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. - * This method is only invoked on a single instance of the interceptor, and not on every instance created. - * @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. - * This method is only invoked on a single instance of the interceptor, and not on every instance created. - * @param pool - the pool that is being closed. - */ - public void poolStarted(ConnectionPool pool) { - // NOOP - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java deleted file mode 100644 index f5fd28e83..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - -import java.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; - -/** - * EXPERIMENTAL AND NOT YET COMPLETE! - * - * - * 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. - *
- * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented. - * @author Filip Hanik - * - */ - -public class MultiLockFairBlockingQueue implements BlockingQueue { - - 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[] items; - - /** - * All threads waiting for an object are stored in a linked list - */ - final LinkedList>[] waiters; - - /** - * Creates a new fair blocking queue. - */ - public MultiLockFairBlockingQueue() { - items = new LinkedList[LOCK_COUNT]; - waiters = new LinkedList[LOCK_COUNT]; - for (int i=0; i(); - waiters[i] = new LinkedList>(); - 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 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 c = new ExchangeCountDownLatch(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 pollAsync() { - int idx = getNextPoll(); - Future 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 c = new ExchangeCountDownLatch(1); - waiters[idx].addLast(c); - lock.unlock(); - //return a future that will wait for the object - result = new ItemFuture(c); - } else { - lock.unlock(); - //return a future with the item - result = new ItemFuture(item); - } - error = false; - } finally { - if (error && lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - return result; - } - - /** - * {@inheritDoc} - */ - public boolean remove(Object e) { - for (int idx=0; idx 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 c, int maxElements) { - throw new UnsupportedOperationException("int drainTo(Collection c, int maxElements)"); - } - - /** - * {@inheritDoc} - * @throws UnsupportedOperationException - this operation is not supported - */ - public int drainTo(Collection 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 c) { - Iterator 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[] toArray(T[] a) { - throw new UnsupportedOperationException(" 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 implements Future { - protected volatile T item = null; - protected volatile ExchangeCountDownLatch latch = null; - protected volatile boolean canceled = false; - - public ItemFuture(T item) { - this.item = item; - } - - public ItemFuture(ExchangeCountDownLatch 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 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[] elements = null; - int index; - E element = null; - - public FairIterator() { - ArrayList list = new ArrayList(MultiLockFairBlockingQueue.this.size()); - for (int idx=0; idx - * 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 - * - boolean result = getTimeBetweenEvictionRunsMillis()>0; - result = result && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0); - result = result || (isTestWhileIdle() && getValidationQuery()!=null); - return result; - - * - * @return true if a background thread is or will be enabled for this pool - */ - public boolean isPoolSweeperEnabled(); - - /** - * Set to true if you wish the ProxyConnection class to use String.equals instead of - * == when comparing method names. - * This property does not apply to added interceptors as those are configured individually. - * The default value is false. - * @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 ProxyConnection class to use String.equals instead of - * == when comparing method names. - * This property does not apply to added interceptors as those are configured individually. - * The default value is false. - * @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 diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java deleted file mode 100644 index 6fd20d406..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java +++ /dev/null @@ -1,1053 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - - -import java.io.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 validatorClass = (Class)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; i0; - 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 properties = new HashMap(); - 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 getProperties() { - return properties; - } - - public Class 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)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; - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java deleted file mode 100644 index 0b2a5ed96..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - -import java.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; - } -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java deleted file mode 100644 index e4108b856..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java +++ /dev/null @@ -1,670 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - - -import java.sql.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 attributes = new HashMap(); - - /** - * 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. - *

- * 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 getAttributes() { - return attributes; - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java deleted file mode 100644 index 532cb6a24..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - -import java.lang.reflect.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: - *

    - *
  • {@link java.sql.Connection#close()} - returns the connection to the pool. May be called multiple times.
  • - *
  • {@link java.lang.Object#toString()} - returns a custom string for this object
  • - *
  • {@link javax.sql.PooledConnection#getConnection()} - returns the underlying connection
  • - *
- * By default method comparisons is done on a String reference level, unless the {@link PoolConfiguration#setUseEquals(boolean)} has been called - * with a true 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")+"]"; - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Validator.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Validator.java deleted file mode 100644 index 4f286ef13..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Validator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool; - -import java.sql.Connection; - -/** - * 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); -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/XADataSource.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/XADataSource.java deleted file mode 100644 index ce829d3a6..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/XADataSource.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.pool; - -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); - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java deleted file mode 100644 index 19a13ed73..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool.interceptor; - -import java.lang.reflect.Method; - -import org.apache.tomcat.jdbc.pool.ConnectionPool; -import org.apache.tomcat.jdbc.pool.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[] 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 diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java deleted file mode 100644 index 6da8bd5e7..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool.interceptor; - -import java.lang.reflect.Method; -import 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> perPoolStats = - new ConcurrentHashMap>(); - /** - * the queries that are used for this interceptor. - */ - protected ConcurrentHashMap 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 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() { - - }; - 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 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 queries) { - Iterator 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 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; - } - } - - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java deleted file mode 100644 index 433519c90..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool.interceptor; - -import java.lang.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 mbeans = - new ConcurrentHashMap(); - - - //==============================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 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 queries = perPoolStats.get(poolName); - if (queries!=null) { - Iterator 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 queries = perPoolStats.get(poolName); - if (queries!=null) { - Set> stats = queries.entrySet(); - if (stats!=null) { - result = new CompositeDataSupport[stats.size()]; - Iterator> it = stats.iterator(); - int pos = 0; - while (it.hasNext()) { - Map.Entry 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 properties) { - super.setProperties(properties); - final String threshold = "notifyPool"; - InterceptorProperty p1 = properties.get(threshold); - if (p1!=null) { - this.setNotifyPool(Boolean.parseBoolean(p1.getValue())); - } - } - - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java deleted file mode 100644 index 908eb1c53..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java +++ /dev/null @@ -1,23 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool.interceptor; - -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.OpenDataException; - -public interface SlowQueryReportJmxMBean { - public CompositeData[] getSlowQueriesCD() throws OpenDataException; -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java deleted file mode 100644 index 533211ce7..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java +++ /dev/null @@ -1,261 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool.interceptor; - -import java.lang.reflect.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 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 cacheSizeMap = - new ConcurrentHashMap(); - - 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 cache = new ConcurrentHashMap(); - pcon.getAttributes().put(STATEMENT_CACHE_ATTR,cache); - } - } - } - - @Override - public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) { - ConcurrentHashMap statements = - (ConcurrentHashMap)con.getAttributes().get(STATEMENT_CACHE_ATTR); - - if (statements!=null) { - for (Map.Entry 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 cache = - (ConcurrentHashMap)pcon.getAttributes().get(STATEMENT_CACHE_ATTR); - return cache.get(sql); - } - - public boolean cacheStatement(CachedStatement proxy) { - ConcurrentHashMap cache = - (ConcurrentHashMap)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 cache = - (ConcurrentHashMap)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 { - 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(); - } - - } - -} - - diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java deleted file mode 100644 index 922205e44..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.jdbc.pool.interceptor; - -import java.lang.reflect.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 JdbcInterceptor 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,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 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); - } - } - } -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java deleted file mode 100644 index f05efde7f..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool.interceptor; - -import java.lang.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> statements = new ArrayList>(); - - @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)); - }catch (ClassCastException x) { - //ignore this one - } - return statement; - } - - @Override - public void closeInvoked() { - while (statements.size()>0) { - WeakReference 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); - } - - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml deleted file mode 100644 index e312d053b..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - Slow query - - - - Failed query execution - - - \ No newline at end of file diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java deleted file mode 100644 index 657cf0e8e..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java +++ /dev/null @@ -1,641 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool.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 listeners = new ConcurrentLinkedQueue(); - - 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 - } - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java deleted file mode 100644 index 7632d37c4..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java +++ /dev/null @@ -1,54 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.pool.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 - //================================================================= - - -} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml deleted file mode 100644 index 897782bd9..000000000 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml +++ /dev/null @@ -1,241 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/modules/jdbc-pool/pom.xml b/modules/jdbc-pool/pom.xml new file mode 100644 index 000000000..1cc288907 --- /dev/null +++ b/modules/jdbc-pool/pom.xml @@ -0,0 +1,110 @@ + + 4.0.0 + org.apache.tomcat + jdbc-pool + 1.2-SNAPSHOT + jar + + jdbc-pool + http://people.apache.org/~fhanik/jdbc-pool/ + + + UTF-8 + + + + + Development List + dev-subscribe@tomcat.apache.org + dev-unsubscribe@tomcat.apache.org + dev@tomcat.apache.org + + + Users List + users-subscribe@tomcat.apache.org + users-unsubscribe@tomcat.apache.org + users@tomcat.apache.org + + + + + + apache.snapshots.https + Apache Development Snapshot Repository + https://repository.apache.org/content/repositories/snapshots + false + + + + + scm:svn:https://svn.apache.org/repos/asf/tomcat/trunk/modules/jdbc-pool + scm:svn:https://svn.apache.org/repos/asf/tomcat/trunk/modules/jdbc-pool + http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool + + + + + org.apache.tomcat + juli + 6.0.32 + + + junit + junit + 3.8.1 + test + + + org.apache.tomcat + dbcp + 6.0.32 + test + + + com.h2database + h2 + 1.3.152 + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + true + true + true + true + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.2 + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.5.1 + + true + false + + + + + diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java new file mode 100644 index 000000000..5fd7007c5 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java @@ -0,0 +1,218 @@ +/* + * 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: + *

+ * <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"/>
+ * 
+ * + */ +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 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); + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java new file mode 100644 index 000000000..0faccfee6 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java @@ -0,0 +1,1201 @@ +/* + * 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 busy; + + /** + * Contains all the idle connections + */ + private BlockingQueue 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()); + + /** + * 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 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 pcf = ((FairBlockingQueue)idle).pollAsync(); + return new ConnectionFuture(pcf); + } else if (idle instanceof MultiLockFairBlockingQueue) { + Future pcf = ((MultiLockFairBlockingQueue)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 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(properties.getMaxActive(),false); + //busy = new FairBlockingQueue(); + //make space for 10 extra in case we flow over a bit + if (properties.isFairQueue()) { + idle = new FairBlockingQueue(); + //idle = new MultiLockFairBlockingQueue(); + } else { + idle = new ArrayBlockingQueue(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.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() 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 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 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 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, Runnable { + Future 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 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() + * {@inheritDoc} + */ + public void postDeregister() { + if (oname!=null) unregisterJmx(); + } + + /** + * no-op
+ * {@inheritDoc} + */ + public void postRegister(Boolean registrationDone) { + // NOOP + } + + + /** + * no-op
+ * {@inheritDoc} + */ + public void preDeregister() throws Exception { + // NOOP + } + + /** + * If the connection pool MBean exists, it will be registered during this operation.
+ * {@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 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); + } + } + + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java new file mode 100644 index 000000000..32e5a4ed6 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java @@ -0,0 +1,538 @@ +/* + * 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; + +/** + *

JNDI object factory that creates an instance of + * BasicDataSource that has been configured based on the + * RefAddr values of the specified Reference, + * which must match the names and data types of the + * BasicDataSource bean properties.

+ *
+ * Properties available for configuration:
+ * Commons DBCP properties
+ *
    + *
  1. initSQL - A query that gets executed once, right after the connection is established.
  2. + *
  3. testOnConnect - run validationQuery after connection has been established.
  4. + *
  5. validationInterval - avoid excess validation, only run validation at most at this frequency - time in milliseconds.
  6. + *
  7. jdbcInterceptors - a semicolon separated list of classnames extending {@link JdbcInterceptor} class.
  8. + *
  9. jmxEnabled - true of false, whether to register the pool with JMX.
  10. + *
  11. fairQueue - true of false, whether the pool should sacrifice a little bit of performance for true fairness.
  12. + *
+ * @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 + + /** + *

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

+ * + * @param obj The possibly null object containing location or + * reference information that can be used in creating an object + * @param name The name of this object relative to nameCtx + * @param nameCtx The context relative to which the name + * parameter is specified, or null if name + * is relative to the default initial context + * @param environment The possibly null environment that is used in + * creating this object + * + * @exception Exception if an exception occurs creating the instance + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) throws Exception { + + // We only know how to deal with javax.naming.References + // that specify a class name of "javax.sql.DataSource" + if ((obj == null) || !(obj instanceof Reference)) { + return null; + } + Reference ref = (Reference) obj; + 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); + } + } + + /** + *

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

+ * @param propText + * @return Properties + * @throws Exception + */ + static protected Properties getProperties(String propText) throws IOException { + return PoolProperties.getProperties(propText,null); + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java new file mode 100644 index 000000000..e8399913e --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java @@ -0,0 +1,1084 @@ +/* + * 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. + *
+ * 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 unwrap(Class 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 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); + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java new file mode 100644 index 000000000..ea56e8671 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/FairBlockingQueue.java @@ -0,0 +1,512 @@ +/* + * 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. + *
+ * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented. + * @author Filip Hanik + * + */ + +public class FairBlockingQueue implements BlockingQueue { + + /** + * 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 items; + + /** + * All threads waiting for an object are stored in a linked list + */ + final LinkedList> waiters; + + /** + * Creates a new fair blocking queue. + */ + public FairBlockingQueue() { + items = new LinkedList(); + waiters = new LinkedList>(); + } + + //------------------------------------------------------------------ + // 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 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 c = new ExchangeCountDownLatch(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 pollAsync() { + Future 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 c = new ExchangeCountDownLatch(1); + waiters.addLast(c); + lock.unlock(); + //return a future that will wait for the object + result = new ItemFuture(c); + } else { + lock.unlock(); + //return a future with the item + result = new ItemFuture(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 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 c, int maxElements) { + throw new UnsupportedOperationException("int drainTo(Collection c, int maxElements)"); + } + + /** + * {@inheritDoc} + * @throws UnsupportedOperationException - this operation is not supported + */ + + public int drainTo(Collection 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 c) { + Iterator 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[] toArray(T[] a) { + throw new UnsupportedOperationException(" 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 implements Future { + protected volatile T item = null; + protected volatile ExchangeCountDownLatch latch = null; + protected volatile boolean canceled = false; + + public ItemFuture(T item) { + this.item = item; + } + + public ItemFuture(ExchangeCountDownLatch 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 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[] 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 + * 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 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 false 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. + *
+ * 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 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 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. + * This method is only invoked on a single instance of the interceptor, and not on every instance created. + * @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. + * This method is only invoked on a single instance of the interceptor, and not on every instance created. + * @param pool - the pool that is being closed. + */ + public void poolStarted(ConnectionPool pool) { + // NOOP + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java new file mode 100644 index 000000000..f5fd28e83 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/MultiLockFairBlockingQueue.java @@ -0,0 +1,537 @@ +/* + * 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; + +/** + * EXPERIMENTAL AND NOT YET COMPLETE! + * + * + * 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. + *
+ * Not all of the methods of the {@link java.util.concurrent.BlockingQueue} are implemented. + * @author Filip Hanik + * + */ + +public class MultiLockFairBlockingQueue implements BlockingQueue { + + 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[] items; + + /** + * All threads waiting for an object are stored in a linked list + */ + final LinkedList>[] waiters; + + /** + * Creates a new fair blocking queue. + */ + public MultiLockFairBlockingQueue() { + items = new LinkedList[LOCK_COUNT]; + waiters = new LinkedList[LOCK_COUNT]; + for (int i=0; i(); + waiters[i] = new LinkedList>(); + 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 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 c = new ExchangeCountDownLatch(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 pollAsync() { + int idx = getNextPoll(); + Future 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 c = new ExchangeCountDownLatch(1); + waiters[idx].addLast(c); + lock.unlock(); + //return a future that will wait for the object + result = new ItemFuture(c); + } else { + lock.unlock(); + //return a future with the item + result = new ItemFuture(item); + } + error = false; + } finally { + if (error && lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + return result; + } + + /** + * {@inheritDoc} + */ + public boolean remove(Object e) { + for (int idx=0; idx 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 c, int maxElements) { + throw new UnsupportedOperationException("int drainTo(Collection c, int maxElements)"); + } + + /** + * {@inheritDoc} + * @throws UnsupportedOperationException - this operation is not supported + */ + public int drainTo(Collection 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 c) { + Iterator 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[] toArray(T[] a) { + throw new UnsupportedOperationException(" 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 implements Future { + protected volatile T item = null; + protected volatile ExchangeCountDownLatch latch = null; + protected volatile boolean canceled = false; + + public ItemFuture(T item) { + this.item = item; + } + + public ItemFuture(ExchangeCountDownLatch 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 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[] elements = null; + int index; + E element = null; + + public FairIterator() { + ArrayList list = new ArrayList(MultiLockFairBlockingQueue.this.size()); + for (int idx=0; idx + * 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 + * + boolean result = getTimeBetweenEvictionRunsMillis()>0; + result = result && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0); + result = result || (isTestWhileIdle() && getValidationQuery()!=null); + return result; + + * + * @return true if a background thread is or will be enabled for this pool + */ + public boolean isPoolSweeperEnabled(); + + /** + * Set to true if you wish the ProxyConnection class to use String.equals instead of + * == when comparing method names. + * This property does not apply to added interceptors as those are configured individually. + * The default value is false. + * @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 ProxyConnection class to use String.equals instead of + * == when comparing method names. + * This property does not apply to added interceptors as those are configured individually. + * The default value is false. + * @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 diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java new file mode 100644 index 000000000..6fd20d406 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java @@ -0,0 +1,1053 @@ +/* + * 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 validatorClass = (Class)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; i0; + 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 properties = new HashMap(); + 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 getProperties() { + return properties; + } + + public Class 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)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; + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java new file mode 100644 index 000000000..0b2a5ed96 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolUtilities.java @@ -0,0 +1,43 @@ +/* + * 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; + } +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java new file mode 100644 index 000000000..e4108b856 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java @@ -0,0 +1,670 @@ +/* + * 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 attributes = new HashMap(); + + /** + * 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. + *

+ * 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 getAttributes() { + return attributes; + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java new file mode 100644 index 000000000..532cb6a24 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java @@ -0,0 +1,153 @@ +/* + * 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: + *

    + *
  • {@link java.sql.Connection#close()} - returns the connection to the pool. May be called multiple times.
  • + *
  • {@link java.lang.Object#toString()} - returns a custom string for this object
  • + *
  • {@link javax.sql.PooledConnection#getConnection()} - returns the underlying connection
  • + *
+ * By default method comparisons is done on a String reference level, unless the {@link PoolConfiguration#setUseEquals(boolean)} has been called + * with a true 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")+"]"; + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/Validator.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/Validator.java new file mode 100644 index 000000000..4f286ef13 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/Validator.java @@ -0,0 +1,37 @@ +/* + * 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); +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/XADataSource.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/XADataSource.java new file mode 100644 index 000000000..ce829d3a6 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/XADataSource.java @@ -0,0 +1,37 @@ +/* + * 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); + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java new file mode 100644 index 000000000..19a13ed73 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractCreateStatementInterceptor.java @@ -0,0 +1,138 @@ +/* + * 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[] 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 diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java new file mode 100644 index 000000000..6da8bd5e7 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java @@ -0,0 +1,152 @@ +/* + * 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> perPoolStats = + new ConcurrentHashMap>(); + /** + * the queries that are used for this interceptor. + */ + protected ConcurrentHashMap 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 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() { + + }; + 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 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 queries) { + Iterator 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 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; + } + } + + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java new file mode 100644 index 000000000..433519c90 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java @@ -0,0 +1,307 @@ +/* + * 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 mbeans = + new ConcurrentHashMap(); + + + //==============================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 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 queries = perPoolStats.get(poolName); + if (queries!=null) { + Iterator 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 queries = perPoolStats.get(poolName); + if (queries!=null) { + Set> stats = queries.entrySet(); + if (stats!=null) { + result = new CompositeDataSupport[stats.size()]; + Iterator> it = stats.iterator(); + int pos = 0; + while (it.hasNext()) { + Map.Entry 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 properties) { + super.setProperties(properties); + final String threshold = "notifyPool"; + InterceptorProperty p1 = properties.get(threshold); + if (p1!=null) { + this.setNotifyPool(Boolean.parseBoolean(p1.getValue())); + } + } + + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java new file mode 100644 index 000000000..908eb1c53 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmxMBean.java @@ -0,0 +1,23 @@ +/* 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; +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java new file mode 100644 index 000000000..533211ce7 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementCache.java @@ -0,0 +1,261 @@ +/* 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 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 cacheSizeMap = + new ConcurrentHashMap(); + + 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 cache = new ConcurrentHashMap(); + pcon.getAttributes().put(STATEMENT_CACHE_ATTR,cache); + } + } + } + + @Override + public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) { + ConcurrentHashMap statements = + (ConcurrentHashMap)con.getAttributes().get(STATEMENT_CACHE_ATTR); + + if (statements!=null) { + for (Map.Entry 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 cache = + (ConcurrentHashMap)pcon.getAttributes().get(STATEMENT_CACHE_ATTR); + return cache.get(sql); + } + + public boolean cacheStatement(CachedStatement proxy) { + ConcurrentHashMap cache = + (ConcurrentHashMap)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 cache = + (ConcurrentHashMap)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 { + 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(); + } + + } + +} + + diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java new file mode 100644 index 000000000..922205e44 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java @@ -0,0 +1,279 @@ +/* + * 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 JdbcInterceptor 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,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 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); + } + } + } +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java new file mode 100644 index 000000000..f05efde7f --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java @@ -0,0 +1,75 @@ +/* + * 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> statements = new ArrayList>(); + + @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)); + }catch (ClassCastException x) { + //ignore this one + } + return statement; + } + + @Override + public void closeInvoked() { + while (statements.size()>0) { + WeakReference 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); + } + + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml new file mode 100644 index 000000000..e312d053b --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/mbeans-descriptors.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + Slow query + + + + Failed query execution + + + \ No newline at end of file diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java new file mode 100644 index 000000000..657cf0e8e --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java @@ -0,0 +1,641 @@ +/* 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 listeners = new ConcurrentLinkedQueue(); + + 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 + } + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java new file mode 100644 index 000000000..7632d37c4 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java @@ -0,0 +1,54 @@ +/* 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 + //================================================================= + + +} diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml new file mode 100644 index 000000000..897782bd9 --- /dev/null +++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestInterceptor.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestInterceptor.java new file mode 100644 index 000000000..739347c8c --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/interceptor/TestInterceptor.java @@ -0,0 +1,59 @@ +/* + * 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 properties) { + instancecount.incrementAndGet(); + super.setProperties(properties); + } + + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java new file mode 100644 index 000000000..a86e6e970 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java @@ -0,0 +1,116 @@ +/* + * 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> results = svc.invokeAll(Arrays.asList(runners)); + int failures = 0; + int total = 0; + for (int i=0; i { + 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 cf = ((DataSourceProxy)datasource).getConnectionAsync(); + Connection con = cf.get(5, TimeUnit.SECONDS); + }finally { + tearDown(); + } + } +} + diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/BorrowWaitTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/BorrowWaitTest.java new file mode 100644 index 000000000..12441409b --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/BorrowWaitTest.java @@ -0,0 +1,70 @@ +/* + * 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(); + } + + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Bug50571.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Bug50571.java new file mode 100644 index 000000000..8a5650cbe --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Bug50571.java @@ -0,0 +1,39 @@ +/* + * 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 org.apache.tomcat.jdbc.pool.interceptor.ConnectionState; + +public class Bug50571 extends DefaultTestCase{ + + public Bug50571(String name) { + super(name); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + this.datasource.setUrl("jdbc:h2:~/.h2/test;QUERY_TIMEOUT=0;DB_CLOSE_ON_EXIT=FALSE"); + this.datasource.setJdbcInterceptors(ConnectionState.class.getName()); + this.datasource.setDefaultTransactionIsolation(-55); + this.datasource.setInitialSize(1); + } + + public void testBug50571() throws Exception { + this.datasource.getConnection().close(); + } +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Bug50805.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Bug50805.java new file mode 100644 index 000000000..80fc23e82 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Bug50805.java @@ -0,0 +1,54 @@ +/* + * 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 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()); + } +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java new file mode 100644 index 000000000..2c5fa5e77 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java @@ -0,0 +1,426 @@ +/* + * 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=ConnectCountTest.this.complete) break; + long start = System.nanoTime(); + Connection con = null; + try { + if (async) { + Future 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); + } + } + } +} + diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/CreateTestTable.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/CreateTestTable.java new file mode 100644 index 000000000..825cb0073 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/CreateTestTable.java @@ -0,0 +1,138 @@ +/* + * 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=FairnessTest.this.complete) break; + long start = System.nanoTime(); + Connection con = null; + try { + if (async) { + Future 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); + } + } + } +} + diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/JmxPasswordTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/JmxPasswordTest.java new file mode 100644 index 000000000..5c63f70bb --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/JmxPasswordTest.java @@ -0,0 +1,71 @@ +/* + * 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 properties = new Hashtable(); + 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)); + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/SimplePOJOAsyncExample.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/SimplePOJOAsyncExample.java new file mode 100644 index 000000000..c3cd07100 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/SimplePOJOAsyncExample.java @@ -0,0 +1,80 @@ +/* + * 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 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 diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/SimplePOJOExample.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/SimplePOJOExample.java new file mode 100644 index 000000000..50368574b --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/SimplePOJOExample.java @@ -0,0 +1,70 @@ +/* + * 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) {} + } + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/StarvationTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/StarvationTest.java new file mode 100644 index 000000000..8013ba535 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/StarvationTest.java @@ -0,0 +1,111 @@ +/* + * 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(); + } + } +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java new file mode 100644 index 000000000..b2570a579 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java @@ -0,0 +1,41 @@ +/* + * 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()); + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestAsyncQueue.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestAsyncQueue.java new file mode 100644 index 000000000..7f21c5208 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestAsyncQueue.java @@ -0,0 +1,86 @@ +/* + * 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 queue = null; + @Override + protected void setUp() throws Exception { + super.setUp(); + this.queue = new FairBlockingQueue(); + } + + @Override + protected void tearDown() throws Exception { + this.queue = null; + super.tearDown(); + } + + + public void testAsyncPoll1() throws Exception { + Object item = new Object(); + queue.offer(item); + Future 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 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); + } + } +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestConcurrency.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestConcurrency.java new file mode 100644 index 000000000..6a22d0a3d --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestConcurrency.java @@ -0,0 +1,211 @@ +/* + * 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= 0); + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java new file mode 100644 index 000000000..33dbec63a --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java @@ -0,0 +1,209 @@ +/* + * 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 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 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 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 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()); + } + } + } + + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java new file mode 100644 index 000000000..d3d57400f --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java @@ -0,0 +1,133 @@ +/* + * 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; + } + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSuspectTimeout.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSuspectTimeout.java new file mode 100644 index 000000000..b4b18d98f --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSuspectTimeout.java @@ -0,0 +1,49 @@ +/* + * 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(); + } +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestTimeout.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestTimeout.java new file mode 100644 index 000000000..6697e9a1c --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestTimeout.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.jdbc.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(); + } + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TwoDataSources.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TwoDataSources.java new file mode 100644 index 000000000..2a500e7ae --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TwoDataSources.java @@ -0,0 +1,65 @@ +/* + * 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); + } + + + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Connection.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Connection.java new file mode 100644 index 000000000..8fc388822 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Connection.java @@ -0,0 +1,238 @@ +/* + * 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> 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> map) throws SQLException { + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + public T unwrap(Class iface) throws SQLException { + return null; + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Driver.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Driver.java new file mode 100644 index 000000000..0b3d8cd00 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Driver.java @@ -0,0 +1,72 @@ +/* + * 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; + } +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/ResultSet.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/ResultSet.java new file mode 100644 index 000000000..9986c48a3 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/ResultSet.java @@ -0,0 +1,1200 @@ +/* + * 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> map) + throws SQLException { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object getObject(String columnLabel, Map> 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 unwrap(Class iface) throws SQLException { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Statement.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Statement.java new file mode 100644 index 000000000..d7d5f9e21 --- /dev/null +++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Statement.java @@ -0,0 +1,1293 @@ +/* + * 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> map) throws SQLException { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object getObject(String parameterName, Map> 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 unwrap(Class iface) throws SQLException { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/pool/interceptor/TestInterceptor.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/pool/interceptor/TestInterceptor.java deleted file mode 100644 index 739347c8c..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/pool/interceptor/TestInterceptor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.pool.interceptor; - -import java.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 properties) { - instancecount.incrementAndGet(); - super.setProperties(properties); - } - - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java deleted file mode 100644 index a86e6e970..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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> results = svc.invokeAll(Arrays.asList(runners)); - int failures = 0; - int total = 0; - for (int i=0; i { - 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 cf = ((DataSourceProxy)datasource).getConnectionAsync(); - Connection con = cf.get(5, TimeUnit.SECONDS); - }finally { - tearDown(); - } - } -} - diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/BorrowWaitTest.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/BorrowWaitTest.java deleted file mode 100644 index 12441409b..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/BorrowWaitTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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(); - } - - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/Bug50571.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/Bug50571.java deleted file mode 100644 index 8a5650cbe..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/Bug50571.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.test; - -import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState; - -public class Bug50571 extends DefaultTestCase{ - - public Bug50571(String name) { - super(name); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - this.datasource.setUrl("jdbc:h2:~/.h2/test;QUERY_TIMEOUT=0;DB_CLOSE_ON_EXIT=FALSE"); - this.datasource.setJdbcInterceptors(ConnectionState.class.getName()); - this.datasource.setDefaultTransactionIsolation(-55); - this.datasource.setInitialSize(1); - } - - public void testBug50571() throws Exception { - this.datasource.getConnection().close(); - } -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/Bug50805.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/Bug50805.java deleted file mode 100644 index 80fc23e82..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/Bug50805.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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 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()); - } -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java deleted file mode 100644 index 2c5fa5e77..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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=ConnectCountTest.this.complete) break; - long start = System.nanoTime(); - Connection con = null; - try { - if (async) { - Future 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); - } - } - } -} - diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/CreateTestTable.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/CreateTestTable.java deleted file mode 100644 index 825cb0073..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/CreateTestTable.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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=FairnessTest.this.complete) break; - long start = System.nanoTime(); - Connection con = null; - try { - if (async) { - Future 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); - } - } - } -} - diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/JmxPasswordTest.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/JmxPasswordTest.java deleted file mode 100644 index 5c63f70bb..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/JmxPasswordTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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 properties = new Hashtable(); - 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)); - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/SimplePOJOAsyncExample.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/SimplePOJOAsyncExample.java deleted file mode 100644 index c3cd07100..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/SimplePOJOAsyncExample.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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 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 diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/SimplePOJOExample.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/SimplePOJOExample.java deleted file mode 100644 index 50368574b..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/SimplePOJOExample.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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) {} - } - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StarvationTest.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StarvationTest.java deleted file mode 100644 index 8013ba535..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StarvationTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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(); - } - } -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java deleted file mode 100644 index b2570a579..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/StatementFinalizerTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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()); - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestAsyncQueue.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestAsyncQueue.java deleted file mode 100644 index 7f21c5208..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestAsyncQueue.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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 queue = null; - @Override - protected void setUp() throws Exception { - super.setUp(); - this.queue = new FairBlockingQueue(); - } - - @Override - protected void tearDown() throws Exception { - this.queue = null; - super.tearDown(); - } - - - public void testAsyncPoll1() throws Exception { - Object item = new Object(); - queue.offer(item); - Future 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 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); - } - } -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestConcurrency.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestConcurrency.java deleted file mode 100644 index 6a22d0a3d..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestConcurrency.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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= 0); - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java deleted file mode 100644 index 33dbec63a..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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 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 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 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 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()); - } - } - } - - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestStatementCache.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestStatementCache.java deleted file mode 100644 index d3d57400f..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestStatementCache.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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; - } - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestSuspectTimeout.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestSuspectTimeout.java deleted file mode 100644 index b4b18d98f..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestSuspectTimeout.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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(); - } -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestTimeout.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestTimeout.java deleted file mode 100644 index 6697e9a1c..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestTimeout.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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(); - } - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TwoDataSources.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TwoDataSources.java deleted file mode 100644 index 2a500e7ae..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TwoDataSources.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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); - } - - - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Connection.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Connection.java deleted file mode 100644 index 8fc388822..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Connection.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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> 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> map) throws SQLException { - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } - - public T unwrap(Class iface) throws SQLException { - return null; - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Driver.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Driver.java deleted file mode 100644 index 0b3d8cd00..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Driver.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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; - } -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/ResultSet.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/ResultSet.java deleted file mode 100644 index 9986c48a3..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/ResultSet.java +++ /dev/null @@ -1,1200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jdbc.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> map) - throws SQLException { - // TODO Auto-generated method stub - return null; - } - - @Override - public Object getObject(String columnLabel, Map> 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 unwrap(Class iface) throws SQLException { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Statement.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Statement.java deleted file mode 100644 index d7d5f9e21..000000000 --- a/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/driver/Statement.java +++ /dev/null @@ -1,1293 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.jdbc.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> map) throws SQLException { - // TODO Auto-generated method stub - return null; - } - - @Override - public Object getObject(String parameterName, Map> 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 unwrap(Class iface) throws SQLException { - // TODO Auto-generated method stub - return null; - } - -}