All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.log4jdbc.sql.jdbcapi.ConnectionSpy Maven / Gradle / Ivy

There is a newer version: 1.16
Show newest version
/**
 * Copyright 2007-2012 Arthur Blake
 *
 * Licensed 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 net.sf.log4jdbc.sql.jdbcapi;

import java.sql.Array;
import java.sql.CallableStatement;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.sql.SQLClientInfoException;
import java.sql.SQLXML;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import net.sf.log4jdbc.log.SpyLogDelegator;
import net.sf.log4jdbc.log.SpyLogFactory;
import net.sf.log4jdbc.sql.Spy;
import net.sf.log4jdbc.sql.rdbmsspecifics.RdbmsSpecifics;

/**
 * Wraps a JDBC Connection and reports method calls, returns and exceptions.
 *
 * This version is for jdbc 4.
 * 

*

Modifications for log4j2:

*
    *
  • Addition of new constructors, to accept a parameter execTime, * a long defining the time elapsed to open the connection in ms. * (see SpyLogDelegator#connectionOpened(Spy, long) for more details, * and modifications in DriverSpy#connect(String, Properties)). *
  • Modification of the method close() in order to compute * execution time to close the connection (see SpyLogDelegator#connectionClosed(Spy, long), * or before an Exception is thrown if a problem occurs. ) *
  • Addition of a new method ConnectionSpy#reportException(String, SQLException, long) * to log execution time before an Exception is thrown when the connection closing failed. *
* * @author Arthur Blake * @author Frederic Bastian * @author Mathieu Seppey */ public class ConnectionSpy implements Connection, Spy { private Connection realConnection; /** * Get the real underlying Connection that this ConnectionSpy wraps. * * @return the real underlying Connection. */ public Connection getRealConnection() { return realConnection; } private SpyLogDelegator log; private final Integer connectionNumber; private static int lastConnectionNumber = 0; /** * Contains a Mapping of connectionNumber to currently open ConnectionSpy * objects. */ private static final Map connectionTracker = new HashMap(); /** * Get a dump of how many connections are open, and which connection numbers * are open. * * @return an open connection dump. */ public static String getOpenConnectionsDump() { StringBuffer dump = new StringBuffer(); int size; Integer[] keysArr; synchronized (connectionTracker) { size = connectionTracker.size(); if (size==0) { return "open connections: none"; } Set keys = connectionTracker.keySet(); keysArr = keys.toArray(new Integer[keys.size()]); } Arrays.sort(keysArr); dump.append("open connections: "); for (int i=0; i < keysArr.length; i++) { dump.append(keysArr[i]); dump.append(" "); } dump.append("("); dump.append(size); dump.append(")"); return dump.toString(); } /** * Create a new ConnectionSpy that wraps a given Connection. * * @param realConnection "real" Connection that this ConnectionSpy wraps. */ public ConnectionSpy(Connection realConnection) { this(realConnection, DriverSpy.defaultRdbmsSpecifics); } /** * Create a new ConnectionSpy that wraps a given Connection. * * @param realConnection "real" Connection that this ConnectionSpy wraps. * @param execTime a long defining the time in ms * taken to open the connection to realConnection. */ public ConnectionSpy(Connection realConnection, long execTime) { this(realConnection, null, execTime); } /** * Create a new ConnectionSpy that wraps a given Connection. * * @param realConnection "real" Connection that this ConnectionSpy wraps. * @param rdbmsSpecifics the RdbmsSpecifics object for formatting logging appropriate for the Rdbms used. */ public ConnectionSpy(Connection realConnection, RdbmsSpecifics rdbmsSpecifics) { this(realConnection, rdbmsSpecifics, -1L); } /** * Create a new ConnectionSpy that wraps a given Connection. * * @param realConnection "real" Connection that this ConnectionSpy wraps. * @param rdbmsSpecifics the RdbmsSpecifics object for formatting logging appropriate for the Rdbms used. * @param execTime a long defining the time in ms * taken to open the connection to realConnection. * Should be equals to -1 if not used. */ public ConnectionSpy(Connection realConnection, RdbmsSpecifics rdbmsSpecifics, long execTime) { if (rdbmsSpecifics == null) { rdbmsSpecifics = DriverSpy.defaultRdbmsSpecifics; } setRdbmsSpecifics(rdbmsSpecifics); if (realConnection == null) { throw new IllegalArgumentException("Must pass in a non null real Connection"); } this.realConnection = realConnection; log = SpyLogFactory.getSpyLogDelegator(); synchronized (connectionTracker) { connectionNumber = new Integer(++lastConnectionNumber); connectionTracker.put(connectionNumber, this); } log.connectionOpened(this, execTime); reportReturn("new Connection"); } private RdbmsSpecifics rdbmsSpecifics; /** * Set the RdbmsSpecifics object for formatting logging appropriate for the Rdbms used on this connection. * * @param rdbmsSpecifics the RdbmsSpecifics object for formatting logging appropriate for the Rdbms used. */ void setRdbmsSpecifics(RdbmsSpecifics rdbmsSpecifics) { this.rdbmsSpecifics = rdbmsSpecifics; } /** * Get the RdbmsSpecifics object for formatting logging appropriate for the Rdbms used on this connection. * * @return the RdbmsSpecifics object for formatting logging appropriate for the Rdbms used. */ RdbmsSpecifics getRdbmsSpecifics() { return rdbmsSpecifics; } public Integer getConnectionNumber() { return connectionNumber; } public String getClassType() { return "Connection"; } protected void reportException(String methodCall, SQLException exception, String sql) { log.exceptionOccured(this, methodCall, exception, sql, -1L); } protected void reportException(String methodCall, SQLException exception) { log.exceptionOccured(this, methodCall, exception, null, -1L); } protected void reportException(String methodCall, SQLException exception, long execTime) { log.exceptionOccured(this, methodCall, exception, null, execTime); } protected void reportAllReturns(String methodCall, String returnValue) { log.methodReturned(this, methodCall, returnValue); } private boolean reportReturn(String methodCall, boolean value) { reportAllReturns(methodCall, "" + value); return value; } private int reportReturn(String methodCall, int value) { reportAllReturns(methodCall, "" + value); return value; } private T reportReturn(String methodCall, T value) { reportAllReturns(methodCall, "" + value); return value; } private void reportReturn(String methodCall) { reportAllReturns(methodCall, ""); } private void reportClosed(long execTime) { log.connectionClosed(this, execTime); } // forwarding methods @Override public boolean isClosed() throws SQLException { String methodCall = "isClosed()"; try { return reportReturn(methodCall, (realConnection.isClosed())); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public SQLWarning getWarnings() throws SQLException { String methodCall = "getWarnings()"; try { return reportReturn(methodCall, realConnection.getWarnings()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public Savepoint setSavepoint() throws SQLException { String methodCall = "setSavepoint()"; try { return reportReturn(methodCall, realConnection.setSavepoint()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { String methodCall = "releaseSavepoint(" + savepoint + ")"; try { realConnection.releaseSavepoint(savepoint); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public void rollback(Savepoint savepoint) throws SQLException { String methodCall = "rollback(" + savepoint + ")"; try { realConnection.rollback(savepoint); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public DatabaseMetaData getMetaData() throws SQLException { String methodCall = "getMetaData()"; try { return reportReturn(methodCall, realConnection.getMetaData()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public void clearWarnings() throws SQLException { String methodCall = "clearWarnings()"; try { realConnection.clearWarnings(); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public Statement createStatement() throws SQLException { String methodCall = "createStatement()"; try { Statement statement = realConnection.createStatement(); return reportReturn(methodCall, new StatementSpy(this, statement)); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { String methodCall = "createStatement(" + resultSetType + ", " + resultSetConcurrency + ")"; try { Statement statement = realConnection.createStatement(resultSetType, resultSetConcurrency); return reportReturn(methodCall, new StatementSpy(this, statement)); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { String methodCall = "createStatement(" + resultSetType + ", " + resultSetConcurrency + ", " + resultSetHoldability + ")"; try { Statement statement = realConnection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); return reportReturn(methodCall, new StatementSpy(this, statement)); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public void setReadOnly(boolean readOnly) throws SQLException { String methodCall = "setReadOnly(" + readOnly + ")"; try { realConnection.setReadOnly(readOnly); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { String methodCall = "prepareStatement(" + sql + ")"; try { PreparedStatement statement = realConnection.prepareStatement(sql); return reportReturn(methodCall, new PreparedStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { String methodCall = "prepareStatement(" + sql + ", " + autoGeneratedKeys + ")"; try { PreparedStatement statement = realConnection.prepareStatement(sql, autoGeneratedKeys); return reportReturn(methodCall, new PreparedStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { String methodCall = "prepareStatement(" + sql + ", " + resultSetType + ", " + resultSetConcurrency + ")"; try { PreparedStatement statement = realConnection.prepareStatement(sql, resultSetType, resultSetConcurrency); return reportReturn(methodCall, new PreparedStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { String methodCall = "prepareStatement(" + sql + ", " + resultSetType + ", " + resultSetConcurrency + ", " + resultSetHoldability + ")"; try { PreparedStatement statement = realConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); return reportReturn(methodCall, new PreparedStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { //todo: dump the array here? String methodCall = "prepareStatement(" + sql + ", " + columnIndexes + ")"; try { PreparedStatement statement = realConnection.prepareStatement(sql, columnIndexes); return reportReturn(methodCall, new PreparedStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public Savepoint setSavepoint(String name) throws SQLException { String methodCall = "setSavepoint(" + name + ")"; try { return reportReturn(methodCall, realConnection.setSavepoint(name)); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { //todo: dump the array here? String methodCall = "prepareStatement(" + sql + ", " + columnNames + ")"; try { PreparedStatement statement = realConnection.prepareStatement(sql, columnNames); return reportReturn(methodCall, new PreparedStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public Clob createClob() throws SQLException { String methodCall = "createClob()"; try { return reportReturn(methodCall, realConnection.createClob()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public Blob createBlob() throws SQLException { String methodCall = "createBlob()"; try { return reportReturn(methodCall, realConnection.createBlob()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public NClob createNClob() throws SQLException { String methodCall = "createNClob()"; try { return reportReturn(methodCall, realConnection.createNClob()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public SQLXML createSQLXML() throws SQLException { String methodCall = "createSQLXML()"; try { return reportReturn(methodCall, realConnection.createSQLXML()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public boolean isValid(int timeout) throws SQLException { String methodCall = "isValid(" + timeout + ")"; try { return reportReturn(methodCall,realConnection.isValid(timeout)); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { String methodCall = "setClientInfo(" + name + ", " + value + ")"; try { realConnection.setClientInfo(name,value); } catch (SQLClientInfoException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { // todo: dump properties? String methodCall = "setClientInfo(" + properties + ")"; try { realConnection.setClientInfo(properties); } catch (SQLClientInfoException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public String getClientInfo(String name) throws SQLException { String methodCall = "getClientInfo(" + name + ")"; try { return reportReturn(methodCall,realConnection.getClientInfo(name)); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public Properties getClientInfo() throws SQLException { String methodCall = "getClientInfo()"; try { return reportReturn(methodCall,realConnection.getClientInfo()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { //todo: dump elements? String methodCall = "createArrayOf(" + typeName + ", " + elements +")"; try { return reportReturn(methodCall,realConnection.createArrayOf(typeName,elements)); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { //todo: dump attributes? String methodCall = "createStruct(" + typeName + ", " + attributes +")"; try { return reportReturn(methodCall,realConnection.createStruct(typeName, attributes)); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public boolean isReadOnly() throws SQLException { String methodCall = "isReadOnly()"; try { return reportReturn(methodCall,realConnection.isReadOnly()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public void setHoldability(int holdability) throws SQLException { String methodCall = "setHoldability(" + holdability + ")"; try { realConnection.setHoldability(holdability); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public CallableStatement prepareCall(String sql) throws SQLException { String methodCall = "prepareCall(" + sql + ")"; try { CallableStatement statement = realConnection.prepareCall(sql); return reportReturn(methodCall, new CallableStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { String methodCall = "prepareCall(" + sql + ", " + resultSetType + ", " + resultSetConcurrency + ")"; try { CallableStatement statement = realConnection.prepareCall(sql, resultSetType, resultSetConcurrency); return reportReturn(methodCall, new CallableStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { String methodCall = "prepareCall(" + sql + ", " + resultSetType + ", " + resultSetConcurrency + ", " + resultSetHoldability + ")"; try { CallableStatement statement = realConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); return reportReturn(methodCall, new CallableStatementSpy(sql, this, statement)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public void setCatalog(String catalog) throws SQLException { String methodCall = "setCatalog(" + catalog + ")"; try { realConnection.setCatalog(catalog); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public String nativeSQL(String sql) throws SQLException { String methodCall = "nativeSQL(" + sql + ")"; try { return reportReturn(methodCall, realConnection.nativeSQL(sql)); } catch (SQLException s) { reportException(methodCall, s, sql); throw s; } } @Override public Map> getTypeMap() throws SQLException { String methodCall = "getTypeMap()"; try { return reportReturn(methodCall, realConnection.getTypeMap()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { String methodCall = "setAutoCommit(" + autoCommit + ")"; try { realConnection.setAutoCommit(autoCommit); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public String getCatalog() throws SQLException { String methodCall = "getCatalog()"; try { return reportReturn(methodCall, realConnection.getCatalog()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public void setTypeMap(java.util.Map> map) throws SQLException { //todo: dump map?? String methodCall = "setTypeMap(" + map + ")"; try { realConnection.setTypeMap(map); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public void setTransactionIsolation(int level) throws SQLException { String methodCall = "setTransactionIsolation(" + level + ")"; try { realConnection.setTransactionIsolation(level); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public boolean getAutoCommit() throws SQLException { String methodCall = "getAutoCommit()"; try { return reportReturn(methodCall, realConnection.getAutoCommit()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public int getHoldability() throws SQLException { String methodCall = "getHoldability()"; try { return reportReturn(methodCall, realConnection.getHoldability()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public int getTransactionIsolation() throws SQLException { String methodCall = "getTransactionIsolation()"; try { return reportReturn(methodCall, realConnection.getTransactionIsolation()); } catch (SQLException s) { reportException(methodCall, s); throw s; } } @Override public void commit() throws SQLException { String methodCall = "commit()"; try { realConnection.commit(); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public void rollback() throws SQLException { String methodCall = "rollback()"; try { realConnection.rollback(); } catch (SQLException s) { reportException(methodCall, s); throw s; } reportReturn(methodCall); } @Override public void close() throws SQLException { String methodCall = "close()"; long tstart = System.currentTimeMillis(); try { realConnection.close(); } catch (SQLException s) { reportException(methodCall, s, System.currentTimeMillis() - tstart); throw s; } finally { synchronized (connectionTracker) { connectionTracker.remove(connectionNumber); } reportClosed(System.currentTimeMillis() - tstart); } reportReturn(methodCall); } @Override public T unwrap(Class iface) throws SQLException { String methodCall = "unwrap(" + (iface==null?"null":iface.getName()) + ")"; try { //todo: double check this logic return (T)reportReturn(methodCall, (iface != null && (iface == Connection.class || iface == Spy.class))?(T)this:realConnection.unwrap(iface)); } catch (SQLException s) { reportException(methodCall,s); throw s; } } @Override public boolean isWrapperFor(Class iface) throws SQLException { String methodCall = "isWrapperFor(" + (iface==null?"null":iface.getName()) + ")"; try { return reportReturn(methodCall, (iface != null && (iface == Connection.class || iface == Spy.class)) || realConnection.isWrapperFor(iface)); } catch (SQLException s) { reportException(methodCall,s); throw s; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy