From: fhanik
Date: Fri, 19 Dec 2008 17:55:46 +0000 (+0000)
Subject: Documented interceptors a bit better, implemented setters for interceptor properties
X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=73daaf112a7c5796e9ad0b4a2108a225daa54e7f;p=tomcat7.0
Documented interceptors a bit better, implemented setters for interceptor properties
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@728081 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/modules/jdbc-pool/build.xml b/modules/jdbc-pool/build.xml
index e8f0178e8..22c75aacc 100644
--- a/modules/jdbc-pool/build.xml
+++ b/modules/jdbc-pool/build.xml
@@ -23,7 +23,7 @@
-
+
diff --git a/modules/jdbc-pool/doc/jdbc-pool.xml b/modules/jdbc-pool/doc/jdbc-pool.xml
index ff8716e15..ba83ecc3a 100644
--- a/modules/jdbc-pool/doc/jdbc-pool.xml
+++ b/modules/jdbc-pool/doc/jdbc-pool.xml
@@ -350,6 +350,75 @@
of the results from a method invokation as well. You could build query performance analyzer that provides JMX notifications when a
query is running longer than the expected time.
+
+
Configuring JDBC interceptors is done using the jdbcInterceptors property.
+ The property contains a list of semi colon separated class names. If the classname if not fully qualified it will be prefixed with the
+ org.apache.tomcat.jdbc.pool.interceptor. prefix.
+ Example:
+
+ jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
+
+ is the same as
+
+ jdbcInterceptors="ConnectionState;StatementFinalizer"
+
+ Interceptors can have properties as well. These would be configured within the paranthesis of the class names.
+ Example:
+
+ jdbcInterceptors="ConnectionState;StatementFinalizer(useWeakReferences=true,useEquals=true)"
+
+
+
+
+
Abstract base class for all interceptors, can not be instantiated.
+
+
+
(String as boolean) A custom query to be run when a connection is first created.
+ The default value is false.
+
+
+
+
+
+
Caches the connection for the following attributes autoCommit, readOnly,
+ transactionIsolation and catalog.
+ It is a performance enhancement to avoid roundtrip to the database when getters are called or setters are called with an already set value.
+
+
+
+
+
+
Keeps track of all statements created using createStatement, prepareStatement or prepareCall
+ and closes these statements when the connection is returned to the pool.
+
+
+
+
+
+
Keeps track of query performance and issues log entries when queries exceed a time threshold of fail.
+ The log level used is WARN
+
+
+
+
(int as String) The number of milliseconds a query has to exceed before issuing a log alert.
+ The default value is 1000 milliseconds.
+
+
+
+
(int as String) The maximum number of queries to keep track of in order to preserve memory space
+ The default value is 1000.
+
+
+
+
+
+
Extends the SlowQueryReport and in addition to log entries it issues JMX notification
+ for monitoring tools to react to. Inherits all the attributes from its parent class.
+ This class uses Tomcat's JMX engine so it wont work outside of the Tomcat container.
+
+
+
+
@@ -519,15 +588,41 @@
The compare(String,Method) will use the useEquals flag on an interceptor and do either reference comparison or
a string value comparison when the useEquals=true flag is set.
-
+
+
Pool start/stop
+ When the connection pool is started or closed, you can be notifed. You will only be notified once per interceptor class
+ even though it is an instance method. and you will be notified using an interceptor currently not attached to a pool.
+
+ public void poolStarted(ConnectionPool pool) {
+ }
+
+ public void poolClosed(ConnectionPool pool) {
+ }
+
+ When overriding these methods, don't forget to call super if you are extending a class other than JdbcInterceptor
+
Configuring interceptors
Interceptors are configured using the jdbcInterceptors property or the setJdbcInterceptors method.
An interceptor can have properties, and would be configured like this
-
String jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState(useEquals=true,fast=yes)"
+
Interceptor properties
+ Since interceptors can have properties, you need to be able to read the values of these properties within your
+ interceptor. Taking an example like the one above, you can override the setProperties method.
+
+ @Override
+ public void setProperties(Map<String, InterceptorProperty> properties) {
+ super.setProperties(properties);
+ final String myprop = "myprop";
+ InterceptorProperty p1 = properties.get(myprop);
+ if (p1!=null) {
+ setMyprop(Long.parseLong(p1.getValue()));
+ }
+ }
+
+
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
index a9707a72c..09fbd39f1 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
@@ -355,7 +355,7 @@ public class ConnectionPool {
try {
proxies[i].getInterceptorClass().newInstance().poolStarted(this);
}catch (Exception x) {
- log.warn("Unable to inform interceptor of pool start.",x);
+ log.error("Unable to inform interceptor of pool start.",x);
if (jmxPool!=null) jmxPool.notify(jmxPool.NOTIFY_INIT, getStackTrace(x));
close(true);
SQLException ex = new SQLException();
@@ -745,7 +745,7 @@ public class ConnectionPool {
return getStackTrace(x);
}
- protected static String getStackTrace(Exception x) {
+ public static String getStackTrace(Throwable x) {
if (x == null) {
return null;
} else {
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
index 88c694900..6c568420a 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
@@ -20,6 +20,7 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorProperty;
@@ -32,7 +33,7 @@ public abstract class JdbcInterceptor implements InvocationHandler {
public static final String TOSTRING_VAL = "toString";
public static final String ISCLOSED_VAL = "isClosed";
- protected List properties = null;
+ protected Map properties = null;
private JdbcInterceptor next = null;
private boolean useEquals = false;
@@ -75,12 +76,17 @@ public abstract class JdbcInterceptor implements InvocationHandler {
*/
public abstract void reset(ConnectionPool parent, PooledConnection con);
- public List getProperties() {
+ public Map getProperties() {
return properties;
}
- public void setProperties(List 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()));
+ }
}
public boolean isUseEquals() {
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
index 163e14b35..cc75642db 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
@@ -19,7 +19,9 @@ package org.apache.tomcat.jdbc.pool;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
@@ -28,6 +30,8 @@ import java.util.concurrent.atomic.AtomicInteger;
*
*/
public class PoolProperties {
+ public static final String PKG_PREFIX = "org.apache.tomcat.jdbc.pool.interceptor.";
+
protected static AtomicInteger poolCounter = new AtomicInteger(0);
protected Properties dbProperties = new Properties();
protected String url = null;
@@ -430,7 +434,7 @@ public class PoolProperties {
public static class InterceptorDefinition {
protected String className;
- protected List properties = new ArrayList();
+ protected Map properties = new HashMap();
protected volatile Class clazz = null;
public InterceptorDefinition(String className) {
this.className = className;
@@ -445,16 +449,20 @@ public class PoolProperties {
}
public void addProperty(InterceptorProperty p) {
- properties.add(p);
+ properties.put(p.getName(), p);
}
- public List getProperties() {
+ public Map getProperties() {
return properties;
}
public Class extends JdbcInterceptor> getInterceptorClass() throws ClassNotFoundException {
if (clazz==null) {
- clazz = Class.forName(getClassName(), true, this.getClass().getClassLoader());
+ if (getClassName().indexOf(".")<0) {
+ clazz = Class.forName(PoolProperties.PKG_PREFIX+getClassName(), true, this.getClass().getClassLoader());
+ } else {
+ clazz = Class.forName(getClassName(), true, this.getClass().getClassLoader());
+ }
}
return (Class extends JdbcInterceptor>)clazz;
}
@@ -464,6 +472,7 @@ public class PoolProperties {
String name;
String value;
public InterceptorProperty(String name, String value) {
+ assert(name!=null);
this.name = name;
this.value = value;
}
@@ -473,6 +482,17 @@ public class PoolProperties {
public String getValue() {
return value;
}
+ 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;
+ }
}
public boolean isUseEquals() {
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
index 082ce53ea..15cff5f7a 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
@@ -25,6 +25,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.openmbean.CompositeDataSupport;
@@ -38,6 +39,7 @@ import org.apache.juli.logging.LogFactory;
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;
/**
* Slow query report interceptor. Tracks timing of query executions.
@@ -65,7 +67,7 @@ public class SlowQueryReport extends AbstractCreateStatementInterceptor {
/**
* The threshold in milliseconds. If the query is faster than this, we don't measure it
*/
- protected long threshold = 100; //don't report queries less than this
+ protected long threshold = 1000; //don't report queries less than this
/**
* Maximum number of queries we will be storing
*/
@@ -104,6 +106,10 @@ public class SlowQueryReport extends AbstractCreateStatementInterceptor {
public void setThreshold(long threshold) {
this.threshold = threshold;
}
+
+ public void setMaxQueries(int maxQueries) {
+ this.maxQueries = maxQueries;
+ }
/**
* invoked when the connection receives the close request
@@ -214,6 +220,8 @@ public class SlowQueryReport extends AbstractCreateStatementInterceptor {
if (sql!=null) {
QueryStats qs = getQueryStats(sql);
if (qs!=null) qs.failure(System.currentTimeMillis()-start,start);
+ if (log.isWarnEnabled()) log.warn("Failed query["+sql+"] Stacktrace:"+ConnectionPool.getStackTrace(t));
+
}
return sql;
}
@@ -229,6 +237,7 @@ public class SlowQueryReport extends AbstractCreateStatementInterceptor {
if (sql!=null) {
QueryStats qs = getQueryStats(sql);
if (qs!=null) qs.add(delta,start);
+ if (log.isWarnEnabled()) log.warn("Slow query["+sql+"] Time to execute:"+delta+" ms.");
}
return sql;
}
@@ -273,6 +282,26 @@ public class SlowQueryReport extends AbstractCreateStatementInterceptor {
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()));
+ }
+ }
+
+
diff --git a/modules/jdbc-pool/sign.sh b/modules/jdbc-pool/sign.sh
index fd65d1c06..308042b27 100755
--- a/modules/jdbc-pool/sign.sh
+++ b/modules/jdbc-pool/sign.sh
@@ -1,4 +1,4 @@
-VERSION=v1.0.7-beta
+VERSION=v1.0.8-beta
for i in $(find output/release/$VERSION -name "*.zip" -o -name "*.tar.gz"); do
echo Signing $i
echo $1|gpg --passphrase-fd 0 -a -b $i
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
new file mode 100644
index 000000000..23f7cc680
--- /dev/null
+++ b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/pool/interceptor/TestInterceptor.java
@@ -0,0 +1,43 @@
+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/TestInterceptorShortName.java b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestInterceptorShortName.java
new file mode 100644
index 000000000..226ef3a3e
--- /dev/null
+++ b/modules/jdbc-pool/test/org/apache/tomcat/jdbc/test/TestInterceptorShortName.java
@@ -0,0 +1,31 @@
+package org.apache.tomcat.jdbc.test;
+
+import java.sql.Connection;
+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.interceptor.TestInterceptor;
+
+public class TestInterceptorShortName extends DefaultTestCase {
+
+ public TestInterceptorShortName(String name) {
+ super(name);
+ }
+
+ public void testShortInterceptor() throws Exception {
+ this.datasource = this.createDefaultDataSource();
+ this.datasource.setJdbcInterceptors("TestInterceptor");
+ this.datasource.setMaxActive(1);
+ Connection con = this.datasource.getConnection();
+ assertTrue("Pool should have been started.",TestInterceptor.poolstarted);
+ assertEquals("Only one interceptor should have been called setProperties",1,TestInterceptor.instancecount.get());
+ con.close();
+ this.datasource.close();
+ assertTrue("Pool should have been closed.",TestInterceptor.poolclosed);
+ }
+
+
+
+}