package codeine.db.mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import codeine.jsons.global.MysqlConfigurationJson;
import codeine.utils.exceptions.ConnectToDatabaseException;
import codeine.utils.exceptions.DatabaseException;
import com.google.common.base.Function;
public class DbUtils
{
private static Logger log = Logger.getLogger(DbUtils.class);
private DBConnection dbConnection = new DBConnection();
@Inject
private MysqlHostSelector hostSelector;
public DbUtils() {
super();
}
public DbUtils(MysqlHostSelector hostSelector) {
super();
this.hostSelector = hostSelector;
}
public static void closeStatement(Statement stmt)
{
if(stmt != null)
{
try
{
stmt.close();
}
catch(SQLException e)
{
log.debug("closeStatement() - failed to close stmt", e);
}
}
}
public static Statement closeResultSet(ResultSet rs)
{
Statement stmt = null;
if(rs != null)
{
try
{
stmt = rs.getStatement();
rs.close();
}
catch(SQLException e)
{
log.debug("closeResultSet() - failed to close rs", e);
}
}
return stmt;
}
public void executeQueryAsRoot(String sql, Function<ResultSet, Void> function) {
executeQuery(sql, function, true, false);
}
public void executeQuery(String sql, Function<ResultSet, Void> function){
executeQuery(sql, function, false, false);
}
public void executeQueryCompressed(String sql, Function<ResultSet, Void> function){
executeQuery(sql, function, false, true);
}
private void executeQuery(String sql, Function<ResultSet, Void> function, boolean root, boolean useCompression)
{
ResultSet rs = null;
Connection connection = root ? getConnectionForRoot(useCompression) : getConnection(useCompression);
try {
PreparedStatement preparedStatement = connection.prepareStatement(sql);
rs = preparedStatement.executeQuery();
while (rs.next()) {
function.apply(rs);
}
} catch (SQLException e) {
throw prepareException(sql, connection, e, null);
} finally {
closeResultSet(rs);
dbConnection.closeConnection(connection);
}
}
private DatabaseException prepareException(String sql, Connection connection, SQLException e, String[] args) {
try {
return new DatabaseException(sql, connection.getMetaData().getURL(), e, args);
} catch (SQLException e1) {
return new DatabaseException(sql, "url could not be resolved", e, args);
}
}
public void executeUpdateableQuery(String sql, Function<ResultSet, Void> function)
{
ResultSet rs = null;
Connection connection = getConnection(false);
try {
PreparedStatement preparedStatement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
rs = preparedStatement.executeQuery();
while (rs.next()) {
function.apply(rs);
}
} catch (SQLException e) {
throw prepareException(sql, connection, e, null);
} finally {
closeResultSet(rs);
dbConnection.closeConnection(connection);
}
}
public int executeUpdate(String sql, String... args) {
return executeUpdate(sql, false, args);
}
private int executeUpdate(String sql, boolean root, String... args) {
PreparedStatement preparedStatement = null;
Connection connection = root ? getConnectionForRoot(true) : getConnection(true);
try {
preparedStatement = connection.prepareStatement(sql);
for (int i = 1; i <= args.length; i++) {
preparedStatement.setString(i, args[i-1]);
}
return preparedStatement.executeUpdate();
} catch (SQLException e) {
throw prepareException(sql, connection, e, args);
} finally {
closeStatement(preparedStatement);
dbConnection.closeConnection(connection);
}
}
public int executeUpdateAsRoot(String sql) {
return executeUpdate(sql, true);
}
private Connection getConnection(boolean useCompression) {
String url = "jdbc:mysql://"+hostSelector.mysql().host()+":" + hostSelector.mysql().port() + "/" + MysqlConstants.DB_NAME + "?connectTimeout=10000";
if (useCompression) {
url += "&useCompression=true";
}
try {
return DriverManager.getConnection(url, hostSelector.mysql().user(), hostSelector.mysql().password());
} catch (SQLException e) {
throw new ConnectToDatabaseException(url, e);
}
}
private Connection getConnectionForRoot(boolean useCompression) {
String url = "jdbc:mysql://localhost:" + hostSelector.mysql().port() + "/" + MysqlConstants.DB_NAME + "?user=root&" + "createDatabaseIfNotExist=true";
if (useCompression) {
url += "&useCompression=true";
}
try {
return DriverManager.getConnection(url);
} catch (SQLException e) {
throw new ConnectToDatabaseException(url, e);
}
}
@Override
public String toString() {
return "DbUtils [" + server() + "]";
}
public String server() {
MysqlConfigurationJson mysql = hostSelector.mysql();
String hostPort = mysql == null ? "null" : mysql.hostPort();
return hostPort;
}
}