Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
/**
* Abstract class that wraps statements and intercepts query executions.
*
*/
public abstract class AbstractQueryReport extends AbstractCreateStatementInterceptor {
//logger
private static final Log log = LogFactory.getLog(AbstractQueryReport.class);
/**
* The threshold in milliseconds. If the query is faster than this, we don't measure it
*/
protected long threshold = 1000; //don't report queries less than this
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 threshold 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 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
*
*/
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;
}
@Override
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
&& t.getCause() != null) {
throw t.getCause();
} 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;
}
}
}