ConnectionHandle implements Connection,Serializable { public void close() throws SQLException { try { if (this.resetConnectionOnClose ){ rollback(); if (!getAutoCommit()){ setAutoCommit(true); } } if (this.logicallyClosed.compareAndSet(false, true)) { if (this.threadWatch != null){ this.threadWatch.interrupt(); this.threadWatch = null; } if (this.closeOpenStatements){ for (Entry<Statement, String> statementEntry: this.trackedStatement.entrySet()){ statementEntry.getKey().close(); if (this.detectUnclosedStatements){ logger.warn(String.format(UNCLOSED_LOG_ERROR_MESSAGE, statementEntry.getValue())); } } this.trackedStatement.clear(); } if (!this.connectionTrackingDisabled){ pool.getFinalizableRefs().remove(this.connection); } ConnectionHandle handle = null; try { handle = this.recreateConnectionHandle(); this.pool.connectionStrategy.cleanupConnection(this, handle); this.pool.releaseConnection(handle); } catch(SQLException e) { if (!isClosed()) { this.pool.connectionStrategy.cleanupConnection(this, handle); this.pool.releaseConnection(this); } throw e; } if (this.doubleCloseCheck){ this.doubleCloseException = this.pool.captureStackTrace(CLOSED_TWICE_EXCEPTION_MESSAGE); } } else { if (this.doubleCloseCheck && this.doubleCloseException != null){ String currentLocation = this.pool.captureStackTrace("Last closed trace from thread ["+Thread.currentThread().getName()+"]:\n"); logger.error(String.format(LOG_ERROR_MESSAGE, this.doubleCloseException, currentLocation)); } } } catch (SQLException e) { throw markPossiblyBroken(e); } } protected  ConnectionHandle(Connection connection, ConnectionPartition partition, BoneCP pool, boolean recreating); private  ConnectionHandle(); ConnectionHandle recreateConnectionHandle(); void sendInitSQL(); void clearWarnings(); void close(); void commit(); Properties getClientInfo(); String getClientInfo(String name); boolean isValid(int timeout); boolean isWrapperFor(Class<?> iface); T unwrap(Class<T> iface); void setClientInfo(Properties properties); void setClientInfo(String name, String value); Struct createStruct(String typeName, Object[] attributes); Array createArrayOf(String typeName, Object[] elements); Blob createBlob(); Clob createClob(); NClob createNClob(); SQLXML createSQLXML(); void setSchema(String schema); String getSchema(); void abort(Executor executor); void setNetworkTimeout(Executor executor, int milliseconds); int getNetworkTimeout(); Statement createStatement(); Statement createStatement(int resultSetType, int resultSetConcurrency); Statement createStatement(int resultSetType,
			int resultSetConcurrency, int resultSetHoldability); boolean getAutoCommit(); String getCatalog(); int getHoldability(); DatabaseMetaData getMetaData(); int getTransactionIsolation(); Map<String, Class<?>> getTypeMap(); SQLWarning getWarnings(); boolean isClosed(); boolean isReadOnly(); String nativeSQL(String sql); CallableStatement prepareCall(String sql); CallableStatement prepareCall(String sql, int resultSetType,	int resultSetConcurrency); CallableStatement prepareCall(String sql, int resultSetType,
			int resultSetConcurrency, int resultSetHoldability); PreparedStatement prepareStatement(String sql); PreparedStatement prepareStatement(String sql, int autoGeneratedKeys); PreparedStatement prepareStatement(String sql, int[] columnIndexes); PreparedStatement prepareStatement(String sql, String[] columnNames); PreparedStatement prepareStatement(String sql, int resultSetType,  int resultSetConcurrency); PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability); void releaseSavepoint(Savepoint savepoint); void rollback(); void rollback(Savepoint savepoint); void setAutoCommit(boolean autoCommit); void setCatalog(String catalog); void setHoldability(int holdability); void setReadOnly(boolean readOnly); Savepoint setSavepoint(); Savepoint setSavepoint(String name); void setTransactionIsolation(int level); void setTypeMap(Map<String, Class<?>> map); long getConnectionLastUsedInMs(); @Deprecated long getConnectionLastUsed(); long getConnectionLastResetInMs(); @Deprecated long getConnectionLastReset(); boolean isPossiblyBroken(); ConnectionPartition getOriginatingPartition(); Object getDebugHandle(); void setDebugHandle(Object debugHandle); @Deprecated Connection getRawConnection(); Connection getInternalConnection(); ConnectionHook getConnectionHook(); boolean isLogStatementsEnabled(); void setLogStatementsEnabled(boolean logStatementsEnabled); boolean isConnectionAlive(); void setInternalConnection(Connection rawConnection); BoneCP getPool(); List<ReplayLog> getReplayLog(); Object getProxyTarget(); Thread getThreadUsingConnection(); @Deprecated long getConnectionCreationTime(); long getConnectionCreationTimeInMs(); boolean isExpired(); Thread getThreadWatch(); void refreshConnection(); String getUrl(); String toString();  }
@Test public void testClose() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SQLException, InterruptedException{ this.testClass.doubleCloseCheck = true; Connection mockInternalConnection = EasyMock.createNiceMock(Connection.class); this.testClass.setInternalConnection(mockInternalConnection); this.testClass.renewConnection(); this.mockPool.releaseConnection((Connection)anyObject()); expectLastCall().once().andThrow(new SQLException()).once(); expect(this.mockPool.getFinalizableRefs()).andReturn(new HashMap<Connection, Reference<ConnectionHandle>>()).anyTimes(); expect(this.mockPool.getConfig()).andReturn(this.config).anyTimes(); expect(mockInternalConnection.isClosed()).andReturn(false).anyTimes(); replay(this.mockPool, mockInternalConnection); Thread testThread = new Thread(new Runnable() { public void run() { try { TestConnectionHandle.this.started = true; while(true){ Thread.sleep(20); } } catch (Exception e) { TestConnectionHandle.this.interrupted = true; } } }); testThread.start(); while (!this.started){ Thread.sleep(20); } this.testClass.setThreadWatch(testThread); this.testClass.close(); testThread.join(); assertTrue(this.interrupted); Assert.assertTrue(this.testClass.logicallyClosed.get()); assertTrue(this.testClass.isClosed()); this.testClass.renewConnection(); try{ this.testClass.close(); fail("Should have thrown an exception"); } catch (Throwable t){ } }
@Test public void testDoubleClose() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, SQLException{ this.testClass.doubleCloseCheck = true; this.testClass.logicallyClosed.set(true); this.testClass.doubleCloseException = "fakeexception"; this.mockLogger.error((String)anyObject(), anyObject()); expectLastCall().once(); this.mockPool.releaseConnection((Connection)anyObject()); expectLastCall().once().andThrow(new SQLException()).once(); replay(this.mockLogger, this.mockPool); this.testClass.close(); }
@Test public void testDoubleCloseNoLogging() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, SQLException{ this.testClass.doubleCloseCheck = true; this.testClass.logicallyClosed.set(true); this.testClass.doubleCloseException = null; this.mockPool.releaseConnection((Connection)anyObject()); expectLastCall().once().andThrow(new SQLException()).once(); replay( this.mockPool); this.testClass.close(); }