class ConnectionPartition implements Serializable {

	protected void trackConnectionFinalizer(ConnectionHandle connectionHandle) {
		if (!this.disableTracking){
		//	assert !connectionHandle.getPool().getFinalizableRefs().containsKey(connectionHandle) : "Already tracking this handle";
			Connection con = connectionHandle.getInternalConnection();
			if (con != null && con instanceof Proxy && Proxy.getInvocationHandler(con) instanceof MemorizeTransactionProxy){
				try {
					// if this is a proxy, get the correct target so that when we call close we're actually calling close on the database
					// handle and not a proxy-based close.
					con = (Connection) Proxy.getInvocationHandler(con).invoke(con, ConnectionHandle.class.getMethod("getProxyTarget"), null);
				} catch (Throwable t) {
					logger.error("Error while attempting to track internal db connection", t); // should never happen
				}
			}
			final Connection internalDBConnection = con;
			final BoneCP pool = connectionHandle.getPool();
			connectionHandle.getPool().getFinalizableRefs().put(internalDBConnection, new FinalizableWeakReference<ConnectionHandle>(connectionHandle, connectionHandle.getPool().getFinalizableRefQueue()) {
				@SuppressWarnings("synthetic-access")
				public void finalizeReferent() {
					try {
						pool.getFinalizableRefs().remove(internalDBConnection);
						if (internalDBConnection != null && !internalDBConnection.isClosed()){ // safety!
							
							logger.warn("BoneCP detected an unclosed connection "+ConnectionPartition.this.poolName + "and will now attempt to close it for you. " +
							"You should be closing this connection in your application - enable connectionWatch for additional debugging assistance or set disableConnectionTracking to true to disable this feature entirely.");
							internalDBConnection.close();
							updateCreatedConnections(-1);
						}
					} catch (Throwable t) {
						logger.error("Error while closing off internal db connection", t);
					}
				}
			});
		}
	}

}

class TestConnectionPartition {

	private BoneCP mockPool;
	private Logger mockLogger;
	private BoneCPConfig mockConfig;
	private ConnectionPartition testClass;

	@Test
	public void testFinalizerException2() throws SQLException, InterruptedException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{

		ConnectionHandle mockConnectionHandle = createNiceMock(ConnectionHandle.class); 
		expect(mockConnectionHandle.isInReplayMode()).andReturn(true).anyTimes();
		Connection mockConnection = createNiceMock(Connection.class);
		Connection connection = new MemorizeTransactionProxyDummy(null,null).memorizeDummy(mockConnection, mockConnectionHandle);
		expect(mockConnectionHandle.getInternalConnection()).andReturn(connection).anyTimes();
		makeThreadSafe(mockConnectionHandle, true);
		makeThreadSafe(mockConnection, true);
		mockLogger = TestUtils.mockLogger(testClass.getClass());
		
		reset(mockLogger);
		makeThreadSafe(mockLogger, true);
		reset(this.mockPool);
		Map<Connection, Reference<ConnectionHandle>> refs = new HashMap<Connection, Reference<ConnectionHandle>>();
		expect(this.mockPool.getFinalizableRefs()).andReturn(refs).anyTimes();
		FinalizableReferenceQueue finalizableRefQueue = new FinalizableReferenceQueue();
		expect(this.mockPool.getFinalizableRefQueue()).andReturn(finalizableRefQueue).anyTimes();
		expect(mockConnectionHandle.getPool()).andReturn(this.mockPool).anyTimes();

		replay(mockConnection, mockConnectionHandle, this.mockPool);

		testClass.trackConnectionFinalizer(mockConnectionHandle);
		reset(mockConnectionHandle);
		mockConnectionHandle = null; // prompt GC to kick in
		for (int i=0; i < 100; i++){
			System.gc();System.gc();System.gc();
			Thread.sleep(20);
			try{
				verify(mockConnection);
				break; // we succeeded
			} catch (Throwable t){
				t.printStackTrace();
				// do nothing, try again
				Thread.sleep(20);
			}
		}
	}

}