/** * TestCube is an enterprise Test management tool. * Copyright (C) 2011 JatakaSource Ltd. * * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * TestCube is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with TestCube. If not, see <http://www.gnu.org/licenses/>. */ package org.jatakasource.testcube.database.dbcp; import java.sql.Connection; import java.sql.SQLException; import javax.annotation.PostConstruct; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.jatakasource.common.thread.ThreadUtils; /** * Extending class of the connection pool manager in order to monitor pooling * exceptions */ public class BasicDataSource extends org.apache.commons.dbcp.BasicDataSource { private static final Logger logger = Logger.getLogger(BasicDataSource.class); // Default wait is 5 minutes private static final int MAX_RETRY = 60; private static final int SLEEP_TIME_MILL = 5000; // 5 seconds private volatile boolean hadError = false; private int maxRetry = MAX_RETRY; private int sleepTimeMill = SLEEP_TIME_MILL; @PostConstruct protected void waitToDB() { // Disable exception logging hadError = true; waitToDB(0); // Enable exception logging hadError = false; } /** * @param counter */ private void waitToDB(int counter) { logger.trace("Checking database connectivity !!!"); Connection connection = null; try { connection = getConnection(); } catch (Throwable e) { logger.debug(e); } if (connection == null) { if (counter >= maxRetry) { logger.error("Unable to establish database (" + getDatabaseVendor() + ") connection !!! maxRetry: " + maxRetry + " counter: " + counter); return; } logger.info("Unable to get database connection " + getDBDetails() + ", sleeping for " + sleepTimeMill + " milliseconds ..."); ThreadUtils.sleepSilently(sleepTimeMill); logger.info("Retry to get database connection (" + counter + " of " + maxRetry + ")"); waitToDB(++counter); } } private String getDBDetails() { return "(" + super.getUrl() + ")"; } @Override public Connection getConnection() throws SQLException { try { Connection connection = super.getConnection(); if (connection.isReadOnly()) { logger.warn("About to provide a read-only connection!"); } if (connection.isClosed()) { logger.warn("About to provide a closed connection!"); } hadError = false; return connection; } catch (RuntimeException e) { logError("Error getting a connetion. Status-> " + getStatus(), e); throw e; } catch (SQLException e) { logError("Error getting a connetion. Status-> " + getStatus(), e); throw e; } } private void logError(String errorMsg, Throwable t) { logger.error(errorMsg + " Exception Message: " + t.getMessage() + " Exception Cause: " + t.getCause()); if (!hadError) { logger.debug(t); hadError = true; } } private String getStatus() { StringBuilder sb = new StringBuilder(); sb.append("Connections: "); sb.append(getNumActive()); sb.append(" active, "); sb.append(getNumIdle()); sb.append(" idle."); return sb.toString(); } /** * Just for debug output messages. */ private String getDatabaseVendor() { if (StringUtils.isEmpty(getDriverClassName())) { return StringUtils.EMPTY; } if (getDriverClassName().toLowerCase().contains("db2")) { return "DB2"; } else if (getDriverClassName().toLowerCase().contains("mysql")) { return "MySQL"; } else if (getDriverClassName().toLowerCase().contains("oracle")) { return "Oracle"; } return StringUtils.EMPTY; } public int getMaxRetry() { return maxRetry; } public void setMaxRetry(int maxRetry) { this.maxRetry = maxRetry; } public int getSleepTimeMill() { return sleepTimeMill; } public void setSleepTimeMill(int sleepTimeMill) { this.sleepTimeMill = sleepTimeMill; } }