Skip to content

Commit

Permalink
refactor: use a connection proxy to log connection commit/rollback/close
Browse files Browse the repository at this point in the history
  • Loading branch information
mjeanroy committed Nov 15, 2023
1 parent 1ca81bf commit 9706f94
Show file tree
Hide file tree
Showing 10 changed files with 463 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ public AbstractJdbcConnectionFactory() {
@Override
public Connection getConnection() {
try {
return createConnection();
return ConnectionProxy.of(
createConnection()
);
}
catch (Exception ex) {
log.error(ex.getMessage(), ex);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,380 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2015-2023 Mickael Jeanroy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package com.github.mjeanroy.dbunit.core.jdbc;

import com.github.mjeanroy.dbunit.commons.lang.ToStringBuilder;
import com.github.mjeanroy.dbunit.loggers.Logger;
import com.github.mjeanroy.dbunit.loggers.Loggers;

import javax.sql.DataSource;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.Executor;

import static com.github.mjeanroy.dbunit.commons.lang.PreConditions.notNull;

/**
* Wrapper for {@link DataSource}, that allows to add some logs when a new connection is created.
*/
final class ConnectionProxy implements Connection {

private static final Logger log = Loggers.getLogger(ConnectionProxy.class);

/**
* Returns given {@code connection} if it is already a proxy, otherwise
* wrap it in a proxy and returns the new proxy instance.
*
* @param connection Connection.
* @return The proxied connection.
*/
static ConnectionProxy of(Connection connection) {
if (connection instanceof ConnectionProxy) {
return (ConnectionProxy) connection;
}

return new ConnectionProxy(connection);
}

private final Connection connection;

private ConnectionProxy(Connection connection) {
this.connection = notNull(connection, "Connection must not be null");
}

@Override
public Statement createStatement() throws SQLException {
return connection.createStatement();
}

@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return connection.prepareStatement(sql);
}

@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return connection.prepareCall(sql);
}

@Override
public String nativeSQL(String sql) throws SQLException {
return connection.nativeSQL(sql);
}

@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
connection.setAutoCommit(autoCommit);
}

@Override
public boolean getAutoCommit() throws SQLException {
return connection.getAutoCommit();
}

@Override
public void commit() throws SQLException {
log.debug("Committing connection");
connection.commit();
}

@Override
public void rollback() throws SQLException {
log.debug("Rollbacking connection");
connection.rollback();
}

@Override
public void close() throws SQLException {
log.debug("Closing connection");
connection.close();
}

@Override
public boolean isClosed() throws SQLException {
return connection.isClosed();
}

@Override
public DatabaseMetaData getMetaData() throws SQLException {
return connection.getMetaData();
}

@Override
public void setReadOnly(boolean readOnly) throws SQLException {
connection.setReadOnly(readOnly);
}

@Override
public boolean isReadOnly() throws SQLException {
return connection.isReadOnly();
}

@Override
public void setCatalog(String catalog) throws SQLException {
connection.setCatalog(catalog);
}

@Override
public String getCatalog() throws SQLException {
return connection.getCatalog();
}

@Override
public void setTransactionIsolation(int level) throws SQLException {
connection.setTransactionIsolation(level);
}

@Override
public int getTransactionIsolation() throws SQLException {
return connection.getTransactionIsolation();
}

@Override
public SQLWarning getWarnings() throws SQLException {
return connection.getWarnings();
}

@Override
public void clearWarnings() throws SQLException {
connection.clearWarnings();
}

@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return connection.createStatement(resultSetType, resultSetConcurrency);
}

@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
}

@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
}

@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
return connection.getTypeMap();
}

@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
connection.setTypeMap(map);
}

@Override
public void setHoldability(int holdability) throws SQLException {
connection.setHoldability(holdability);
}

@Override
public int getHoldability() throws SQLException {
return connection.getHoldability();
}

@Override
public Savepoint setSavepoint() throws SQLException {
return connection.setSavepoint();
}

@Override
public Savepoint setSavepoint(String name) throws SQLException {
return connection.setSavepoint(name);
}

@Override
public void rollback(Savepoint savepoint) throws SQLException {
connection.rollback(savepoint);
}

@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
connection.releaseSavepoint(savepoint);
}

@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
}

@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}

@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}

@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return connection.prepareStatement(sql, autoGeneratedKeys);
}

@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return connection.prepareStatement(sql, columnIndexes);
}

@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return connection.prepareStatement(sql, columnNames);
}

@Override
public Clob createClob() throws SQLException {
return connection.createClob();
}

@Override
public Blob createBlob() throws SQLException {
return connection.createBlob();
}

@Override
public NClob createNClob() throws SQLException {
return connection.createNClob();
}

@Override
public SQLXML createSQLXML() throws SQLException {
return connection.createSQLXML();
}

@Override
public boolean isValid(int timeout) throws SQLException {
return connection.isValid(timeout);
}

@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
connection.setClientInfo(name, value);
}

@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
connection.setClientInfo(properties);
}

@Override
public String getClientInfo(String name) throws SQLException {
return connection.getClientInfo(name);
}

@Override
public Properties getClientInfo() throws SQLException {
return connection.getClientInfo();
}

@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return connection.createArrayOf(typeName, elements);
}

@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
return connection.createStruct(typeName, attributes);
}

@Override
public void setSchema(String schema) throws SQLException {
connection.setSchema(schema);
}

@Override
public String getSchema() throws SQLException {
return connection.getSchema();
}

@Override
public void abort(Executor executor) throws SQLException {
connection.abort(executor);
}

@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
connection.setNetworkTimeout(executor, milliseconds);
}

@Override
public int getNetworkTimeout() throws SQLException {
return connection.getNetworkTimeout();
}

@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return connection.unwrap(iface);
}

@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return connection.isWrapperFor(iface);
}

@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}

if (o instanceof ConnectionProxy) {
ConnectionProxy cp = (ConnectionProxy) o;
return Objects.equals(connection, cp.connection);
}

return false;
}

@Override
public int hashCode() {
return Objects.hash(connection);
}

@Override
public String toString() {
return ToStringBuilder.create(getClass())
.append("connection", connection)
.build();
}
}
Loading

0 comments on commit 9706f94

Please sign in to comment.