BoneCP implements Serializable, Closeable { protected Connection obtainInternalConnection(ConnectionHandle connectionHandle) throws SQLException { boolean tryAgain = false; Connection result = null; Connection oldRawConnection = connectionHandle.getInternalConnection(); String url = this.getConfig().getJdbcUrl(); int acquireRetryAttempts = this.getConfig().getAcquireRetryAttempts(); long acquireRetryDelayInMs = this.getConfig().getAcquireRetryDelayInMs(); AcquireFailConfig acquireConfig = new AcquireFailConfig(); acquireConfig.setAcquireRetryAttempts(new AtomicInteger(acquireRetryAttempts)); acquireConfig.setAcquireRetryDelayInMs(acquireRetryDelayInMs); acquireConfig.setLogMessage("Failed to acquire connection to "+url); ConnectionHook connectionHook = this.getConfig().getConnectionHook(); do{ result = null; try { result = this.obtainRawInternalConnection(); tryAgain = false; if (acquireRetryAttempts != this.getConfig().getAcquireRetryAttempts()){ logger.info("Successfully re-established connection to "+url); } this.getDbIsDown().set(false); connectionHandle.setInternalConnection(result); if (connectionHook != null){ connectionHook.onAcquire(connectionHandle); } ConnectionHandle.sendInitSQL(result, this.getConfig().getInitSQL()); } catch (SQLException e) { if (connectionHook != null){ tryAgain = connectionHook.onAcquireFail(e, acquireConfig); } else { logger.error(String.format("Failed to acquire connection to %s. Sleeping for %d ms. Attempts left: %d", url, acquireRetryDelayInMs, acquireRetryAttempts), e); try { if (acquireRetryAttempts > 0){ Thread.sleep(acquireRetryDelayInMs); } tryAgain = (acquireRetryAttempts--) > 0; } catch (InterruptedException e1) { tryAgain=false; } } if (!tryAgain){ if (oldRawConnection != null) { oldRawConnection.close(); } if (result != null) { result.close(); } connectionHandle.setInternalConnection(oldRawConnection); throw e; } } } while (tryAgain); return result; } BoneCP(BoneCPConfig config); synchronized void shutdown(); void close(); Connection getConnection(); ListenableFuture<Connection> getAsyncConnection(); boolean isConnectionHandleAlive(ConnectionHandle connection); int getTotalLeased(); int getTotalFree(); int getTotalCreatedConnections(); BoneCPConfig getConfig(); Statistics getStatistics(); AtomicBoolean getDbIsDown(); static final String MBEAN_CONFIG; static final String MBEAN_BONECP; }
@Test public void testObtainInternalConnection() throws SQLException, ClassNotFoundException, InterruptedException{ expect(this.mockPool.getConfig()).andReturn(mockConfig).anyTimes(); DataSource mockDataSourceBean = EasyMock.createNiceMock(DataSource.class); expect(this.mockConfig.getDatasourceBean()).andReturn(mockDataSourceBean).anyTimes(); expect(mockConfig.getJdbcUrl()).andReturn("jdbc:mock:driver").anyTimes(); mockConfig.setAcquireRetryDelayInMs(1); CustomHook testHook = new CustomHook(); expect(mockConfig.getConnectionHook()).andReturn(testHook).anyTimes(); expect(this.mockPool.getDbIsDown()).andReturn(new AtomicBoolean()).anyTimes(); expect(mockDataSourceBean.getConnection()).andThrow(new SQLException()).once().andReturn(null).once(); expect(mockConnection.getInternalConnection()).andReturn(new MockConnection()).anyTimes(); replay(this.mockPool, mockConfig, mockDataSourceBean, mockConnection); this.testClass.obtainInternalConnection(mockConnection); assertEquals(1, testHook.fail); assertEquals(1, testHook.acquire); reset(this.mockPool, mockDataSourceBean); expect(this.mockPool.getDbIsDown()).andReturn(new AtomicBoolean()).anyTimes(); expect(this.mockPool.getConfig()).andReturn(mockConfig).anyTimes(); expect(mockDataSourceBean.getConnection()).andThrow(new SQLException()).once().andReturn(this.mockConnection).once(); int count=1; mockConfig.setConnectionHook(null); replay(this.mockPool, mockDataSourceBean); assertEquals(this.mockConnection, this.testClass.obtainInternalConnection(mockConnection)); reset(this.mockPool, mockDataSourceBean); expect(this.mockPool.getConfig()).andReturn(mockConfig).anyTimes(); expect(mockDataSourceBean.getConnection()).andThrow(new SQLException()).anyTimes(); replay(this.mockPool, mockDataSourceBean); count=99; mockConfig.setAcquireRetryAttempts(2); try{ this.testClass.obtainInternalConnection(mockConnection); fail("Should have thrown an exception"); } catch (SQLException e){ } count=99; mockConfig.setAcquireRetryAttempts(2); mockConfig.setAcquireRetryDelayInMs(7000); final Thread currentThread = Thread.currentThread(); try{ new Thread(new Runnable() { public void run() { while (!currentThread.getState().equals(State.TIMED_WAITING)){ try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } currentThread.interrupt(); } }).start(); this.testClass.obtainInternalConnection(mockConnection); fail("Should have thrown an exception"); } catch (SQLException e){ } reset(this.mockPool, mockDataSourceBean, mockConfig); expect(this.mockPool.getConfig()).andReturn(mockConfig).anyTimes(); expect(mockDataSourceBean.getConnection()).andThrow(new SQLException()).anyTimes(); mockConfig.setAcquireRetryAttempts(0); replay(this.mockPool, mockDataSourceBean, mockConfig); count=99; try{ this.testClass.obtainInternalConnection(mockConnection); fail("Should have thrown an exception"); } catch (SQLException e){ } mockConfig.setAcquireRetryDelayInMs(10); }