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 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)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); + } + + + +}