<classpathentry kind="src" path="test"/>
<classpathentry combineaccessrules="false" kind="src" path="/tomcat-trunk"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
- <classpathentry kind="var" path="TOMCAT_LIBS_BASE/tomcat6-deps/dbcp/tomcat-dbcp.jar"/>
+ <classpathentry kind="var" path="TOMCAT_LIBS_BASE/tomcat6-deps/dbcp/tomcat-dbcp.jar" sourcepath="/TOMCAT_LIBS_BASE/tomcat6-deps/dbcp/src/java"/>
<classpathentry kind="lib" path="mysql-connector-java-5.1.6-bin.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
/**
+ * Abstract class that is to be extended for implementations of interceptors.
+ *
* @author Filip Hanik
* @version 1.0
*/
public abstract class JdbcInterceptor implements InvocationHandler {
+ /**
+ * java.sql.Connection.close()
+ */
public static final String CLOSE_VAL = "close";
+ /**
+ * java.sql.Connection.toString()
+ */
public static final String TOSTRING_VAL = "toString";
- public static final String ISCLOSED_VAL = "isClosed";
+ /**
+ * java.sql.Connection.isClosed()
+ */
+ public static final String ISCLOSED_VAL = "isClosed";
+ /**
+ * javax.sql.DataSource.getConnection()
+ */
public static final String GETCONNECTION_VAL = "getConnection";
+ /**
+ * Properties for this interceptor
+ */
protected Map<String,InterceptorProperty> properties = null;
+ /**
+ * The next interceptor in the chain
+ */
private JdbcInterceptor next = null;
+ /**
+ * Property that decides how we do string comparison, default is reference (==)
+ */
private boolean useEquals = false;
+ /**
+ * Public constructor for instantation through reflection
+ */
public JdbcInterceptor() {
}
/**
+ * Gets invoked each time an operation on java.sql.Connection is invoked.
* {@inheritDoc}
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
else throw new NullPointerException();
}
+ /**
+ * Returns the next interceptor in the chain
+ * @return
+ */
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
+ */
public boolean compare(String name1, String name2) {
if (isUseEquals()) {
return name1.equals(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.
* @param parent - the connection pool owning the connection
* @param con - the pooled connection
*/
public abstract void reset(ConnectionPool parent, PooledConnection con);
+ /**
+ *
+ * @return the configured properties for this interceptor
+ */
public Map<String,InterceptorProperty> getProperties() {
return properties;
}
+ /**
+ * Called during the creation of an interceptor
+ * The properties can be set during the configuration of an interceptor
+ * @param properties
+ */
public void setProperties(Map<String,InterceptorProperty> properties) {
this.properties = properties;
final String useEquals = "useEquals";
}
}
+ /**
+ * @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} method) should use the Object.equals(Object) method
+ * The default is false
+ * @param useEquals
+ */
public void setUseEquals(boolean useEquals) {
this.useEquals = useEquals;
}
import java.util.concurrent.atomic.AtomicInteger;
/**
+ * Represents a pooled connection
+ * and holds a reference to the java.sql.Connection object
* @author Filip Hanik
* @version 1.0
*/
public class PooledConnection {
+ /**
+ * Logger
+ */
+ protected static Log log = LogFactory.getLog(PooledConnection.class);
+ /**
+ * Instance counter
+ */
+ protected static AtomicInteger counter = new AtomicInteger(01);
+ /**
+ * 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;
- protected static Log log = LogFactory.getLog(PooledConnection.class);
- protected static AtomicInteger counter = new AtomicInteger(01);
-
+ /**
+ * The properties for the connection pool
+ */
protected PoolProperties poolProperties;
+ /**
+ * The underlying database connection
+ */
protected java.sql.Connection connection;
+ /**
+ * When we track abandon traces, this string holds the thread dump
+ */
protected String abandonTrace = null;
+ /**
+ * Timestamp the connection was last 'touched' by the pool
+ */
protected long timestamp;
+ /**
+ * Lock for this connection only
+ */
protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
+ /**
+ * Set to true if this connection has been discarded by the pool
+ */
protected boolean discarded = false;
+ /**
+ * timestamp to keep track of validation intervals
+ */
protected long lastValidated = System.currentTimeMillis();
+ /**
+ * The instance number for this connection
+ */
protected int instanceCount = 0;
+ /**
+ * The parent
+ */
protected ConnectionPool parent;
+ /**
+ * 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
+ */
protected WeakReference<JdbcInterceptor> handler = null;
+
public PooledConnection(PoolProperties prop, ConnectionPool parent) {
instanceCount = counter.addAndGet(1);
poolProperties = prop;
try {
this.disconnect(false);
} catch (Exception x) {
- log.error("Unable to disconnect previous connection.", x);
+ log.debug("Unable to disconnect previous connection.", x);
} //catch
} //end if
java.sql.Driver driver = null;
this.discarded = false;
}
+ /**
+ *
+ * @return true if connect() was called successfully and disconnect has not yet been called
+ */
public boolean isInitialized() {
return connection!=null;
}
this.connect();
} //reconnect
- protected synchronized void disconnect(boolean finalize) {
+ protected void disconnect(boolean finalize) {
if (isDiscarded()) {
return;
}
return poolProperties;
}
+ /**
+ * Locks the connection only if the sweeper thread is enabled
+ * Otherwise this is a noop for performance
+ */
public void lock() {
if (this.poolProperties.isPoolSweeperEnabled()) {
//optimized, only use a lock when there is concurrency
}
}
+ /**
+ * Unlocks the connection only if the sweeper is enabled
+ * Otherwise this is a noop for performance
+ */
public void unlock() {
if (this.poolProperties.isPoolSweeperEnabled()) {
//optimized, only use a lock when there is concurrency
}
}
+ /**
+ * Returns the underlying connection
+ * @return
+ */
public java.sql.Connection getConnection() {
return this.connection;
}
+ /**
+ * Returns the first handler in the interceptor chain
+ * @return
+ */
public JdbcInterceptor getHandler() {
return (handler!=null)?handler.get():null;
}
import org.apache.juli.logging.LogFactory;
public class ConnectionPool extends NotificationBroadcasterSupport implements ConnectionPoolMBean {
- //logger
+ /**
+ * logger
+ */
protected static 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);
public ConnectionPool(org.apache.tomcat.jdbc.pool.ConnectionPool pool) {
datasource.getPoolProperties().setRemoveAbandonedTimeout(5);
datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(500);
datasource.getPoolProperties().setMaxWait(10000);
+ datasource.getPoolProperties().setLogAbandoned(true);
}
public void testDBCPConnectionStarvation() throws Exception {
}finally {
if (con2!=null) con2.close();
}
+
}
public void testConnectionStarvation() throws Exception {