/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.util.db.pool;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import jsr166y.TransferQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jolbox.bonecp.BoneCP;
import com.jolbox.bonecp.ConnectionHandle;
import com.jolbox.bonecp.ConnectionPartition;
import com.jolbox.bonecp.StatementHandle;
import com.jolbox.bonecp.hooks.AcquireFailConfig;
import com.jolbox.bonecp.hooks.ConnectionHook;
import com.jolbox.bonecp.hooks.ConnectionState;
import com.opengamma.util.async.BlockingOperation;
/**
* Hacks a call to {@link BlockingOperation#wouldBlock} into {@link BoneCP} when it would wait for a connection to become available.
*/
public class BoneCPHack implements ConnectionHook {
/** Logger. */
private static final Logger s_logger = LoggerFactory.getLogger(BoneCPHack.class);
private static final Object HACK_PARTITION_FLAG = new Object();
/**
* The underlying connection.
*/
private final ConnectionHook _underlying;
/**
* Creates an instance.
*/
public BoneCPHack() {
this(null);
}
/**
* Creates an instance decorating the underlying hook.
*
* @param underlying the underlying hook
*/
public BoneCPHack(final ConnectionHook underlying) {
_underlying = underlying;
}
//-------------------------------------------------------------------------
@Override
public void onAcquire(ConnectionHandle connection) {
if (_underlying != null) {
_underlying.onAcquire(connection);
}
if (connection.getDebugHandle() == null) {
connection.setDebugHandle(HACK_PARTITION_FLAG);
}
}
@Override
public void onCheckIn(ConnectionHandle connection) {
if (_underlying != null) {
_underlying.onCheckIn(connection);
}
}
@SuppressWarnings("unchecked")
@Override
public void onCheckOut(ConnectionHandle connection) {
if (connection.getDebugHandle() == HACK_PARTITION_FLAG) {
try {
final ConnectionPartition partition = connection.getOriginatingPartition();
final Method getFreeConnections = partition.getClass().getDeclaredMethod("getFreeConnections");
getFreeConnections.setAccessible(true);
TransferQueue<ConnectionHandle> connections = (TransferQueue<ConnectionHandle>) getFreeConnections.invoke(partition);
if (!(connections instanceof TransferQueueWithBlockingOperationHook)) {
synchronized (partition) {
connections = (TransferQueue<ConnectionHandle>) getFreeConnections.invoke(partition);
if (!(connections instanceof TransferQueueWithBlockingOperationHook)) {
final Method setFreeConnections = partition.getClass().getDeclaredMethod("setFreeConnections", TransferQueue.class);
setFreeConnections.setAccessible(true);
setFreeConnections.invoke(partition, new TransferQueueWithBlockingOperationHook<ConnectionHandle>(connections));
}
}
}
} catch (Exception e) {
s_logger.error("Couldn't hack BlockingOperation call into BoneCP", e);
}
connection.setDebugHandle(null);
}
if (_underlying != null) {
_underlying.onCheckOut(connection);
}
}
@Override
public void onDestroy(ConnectionHandle connection) {
if (connection.getDebugHandle() == HACK_PARTITION_FLAG) {
connection.setDebugHandle(null);
}
if (_underlying != null) {
_underlying.onDestroy(connection);
}
}
@Override
public boolean onAcquireFail(Throwable t, AcquireFailConfig acquireConfig) {
if (_underlying != null) {
return _underlying.onAcquireFail(t, acquireConfig);
} else {
return false;
}
}
@Override
public void onQueryExecuteTimeLimitExceeded(ConnectionHandle conn, Statement statement, String sql, Map<Object, Object> logParams, long timeElapsedInNs) {
if (_underlying != null) {
_underlying.onQueryExecuteTimeLimitExceeded(conn, statement, sql, logParams, timeElapsedInNs);
}
}
@SuppressWarnings("deprecation")
@Override
public void onQueryExecuteTimeLimitExceeded(ConnectionHandle conn, Statement statement, String sql, Map<Object, Object> logParams) {
if (_underlying != null) {
_underlying.onQueryExecuteTimeLimitExceeded(conn, statement, sql, logParams);
}
}
@SuppressWarnings("deprecation")
@Override
public void onQueryExecuteTimeLimitExceeded(String sql, Map<Object, Object> logParams) {
if (_underlying != null) {
_underlying.onQueryExecuteTimeLimitExceeded(sql, logParams);
}
}
@Override
public void onBeforeStatementExecute(ConnectionHandle conn, StatementHandle statement, String sql, Map<Object, Object> params) {
if (_underlying != null) {
_underlying.onBeforeStatementExecute(conn, statement, sql, params);
}
}
@Override
public void onAfterStatementExecute(ConnectionHandle conn, StatementHandle statement, String sql, Map<Object, Object> params) {
if (_underlying != null) {
_underlying.onAfterStatementExecute(conn, statement, sql, params);
}
}
@Override
public boolean onConnectionException(ConnectionHandle connection, String state, Throwable t) {
if (_underlying != null) {
return _underlying.onConnectionException(connection, state, t);
} else {
return false;
}
}
@Override
public ConnectionState onMarkPossiblyBroken(ConnectionHandle connection, String state, SQLException e) {
if (_underlying != null) {
return _underlying.onMarkPossiblyBroken(connection, state, e);
} else {
return ConnectionState.NOP;
}
}
}