/*
* This file is part of anycook. The new internet cookbook
* Copyright (C) 2014 Jan Graßegger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see [http://www.gnu.org/licenses/].
*/
package de.anycook.db.mysql;
/**
* enthaelt alle Funktion, die auf die MySQL-Datenbank zugreifen
*/
import com.google.common.base.Preconditions;
import de.anycook.conf.Configuration;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
/**
* Alle MySQL-Zugriffe geschehen ueber diese Klasse. Benutzt connectionpool
*
* @author Jan Grassegger
*/
public class DBHandler implements AutoCloseable {
private static Logger sLogger = LogManager.getLogger(DBHandler.class);
protected static BasicDataSource dataSource;
public static void init() {
String server = Configuration.getInstance().getMysqlAddress();
String db = Configuration.getInstance().getMysqlDb();
int port = Configuration.getInstance().getPropertyMysqlPort();
String user = Configuration.getInstance().getMysqlUser();
String password = Configuration.getInstance().getMysqlPassword();
int maxActive = Configuration.getInstance().getMysqlMaxActive();
int maxIdle = Configuration.getInstance().getMysqlMaxIdle();
dataSource = setupDataSource(server, port, db, user, password, maxActive, maxIdle);
}
protected Logger logger;
protected Connection connection;
/**
* Laedt jdbc-Driver und ruft {@link de.anycook.db.mysql.DBHandler#connect()} auf.
*/
public DBHandler() throws SQLException {
logger = LogManager.getLogger(getClass());
//logger.debug("created new connection");
connect();
checkDataSourceStatus();
}
public DBHandler(DBHandler copy) {
this.connection = copy.connection;
}
/**
* Nur zur Sicherheit, falls jemand vergessen hat die DB-Verbindung zu schließen. Sollte aber
* trotzdem immer gemacht werden!
*/
@Override
protected void finalize() throws Throwable {
super.finalize();
close();
}
private static BasicDataSource setupDataSource(String server, int port, String dbName,
String username,
String password, int maxActive, int maxIdle) {
Preconditions.checkNotNull(server);
Preconditions.checkNotNull(dbName);
Preconditions.checkNotNull(username);
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUsername(username);
if (password.length() > 0) {
ds.setPassword(password);
}
String
url =
String.format("jdbc:mysql://%s:%d/%s?useConfigs=maxPerformance&useCompression=true",
server, port, dbName);
ds.setUrl(url);
ds.setValidationQuery("SELECT 1;");
ds.setTestWhileIdle(true);
ds.setTestOnReturn(true);
ds.setMaxTotal(maxActive);
ds.setMaxIdle(maxIdle);
ds.setRemoveAbandonedOnBorrow(true);
ds.setRemoveAbandonedTimeout(60);
if (Configuration.getInstance().isDeveloperMode()) {
ds.setLogAbandoned(true);
}
sLogger.info("created new Connectionpool");
return ds;
}
public static void closeSource() {
try {
dataSource.close();
dataSource = null;
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
DriverManager.deregisterDriver(drivers.nextElement());
}
} catch (SQLException e) {
sLogger.error(e);
}
}
private void connect() throws SQLException {
if (dataSource == null) {
throw new SQLException("Connection pool has not been initialized");
}
connection = dataSource.getConnection();
}
@Override
public void close() {
try {
connection.close();
connection = null;
} catch (SQLException e) {
logger.debug("failed to close connection", e);
}
//logger.debug("closed a connection");
}
public String toString() {
return "Connection: " + connection;
}
public static void checkDataSourceStatus() {
if (dataSource.getMaxTotal() - dataSource.getNumActive() <= 12) {
sLogger.warn("running out of connections!");
printDataSourceStatus();
}
}
public static void printDataSourceStatus() {
sLogger.info(String.format("MySQLConn. Idle: %d MaxIdle: %d NumActive: %d MaxActive: %d",
dataSource.getNumIdle(), dataSource.getMaxIdle(),
dataSource.getNumActive(), dataSource.getMaxTotal()));
}
public static int getNumActive() {
return dataSource.getNumActive();
}
public static int getMaxActive() {
return dataSource.getMaxTotal();
}
public static int getNumIdle() {
return dataSource.getNumIdle();
}
public static int getMaxIdle() {
return dataSource.getMaxIdle();
}
public static ConnectionStatus getConnectionsStatus() {
ConnectionStatus status = new ConnectionStatus();
status.setNumActive(getNumActive());
status.setMaxActive(getMaxActive());
status.setNumIdle(getNumIdle());
status.setMaxIdle(getMaxIdle());
return status;
}
public static class ConnectionStatus {
private int numActive;
private int maxActive;
private int numIdle;
private int maxIdle;
public int getNumActive() {
return numActive;
}
public void setNumActive(int numActive) {
this.numActive = numActive;
}
public int getMaxActive() {
return maxActive;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public int getNumIdle() {
return numIdle;
}
public void setNumIdle(int numIdle) {
this.numIdle = numIdle;
}
public int getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
}
}