package com.nicewuerfel.blockown.database;
import com.nicewuerfel.blockown.Ownable;
import com.nicewuerfel.blockown.OwnedBlock;
import com.nicewuerfel.blockown.OwnedEntity;
import com.nicewuerfel.blockown.User;
import com.nicewuerfel.blockown.output.Output;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.lang.NullArgumentException;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class MySqlDatabase extends CachedDatabase {
private static final String CREATE_BLOCK_TABLE_QUERY = String.format(
"CREATE TABLE IF NOT EXISTS %1$s (%2$s VARCHAR(50), %3$s INT, %4$s INT, %5$s INT, %6$s CHAR(36) NOT NULL, PRIMARY KEY (%2$s, %3$s, %4$s, %5$s));",
Database.BLOCK_TABLE, Database.WORLD_COLUMN, Database.X_COLUMN, Database.Y_COLUMN,
Database.Z_COLUMN, Database.PLAYER_ID_COLUMN);
private static final String CREATE_ENTITY_TABLE_QUERY = String.format(
"CREATE TABLE IF NOT EXISTS %1$s (%2$s VARCHAR(50) NOT NULL, %3$s CHAR(36), %4$s CHAR(36) NOT NULL, PRIMARY KEY (%3$s));",
Database.ENTITY_TABLE, Database.WORLD_COLUMN, Database.ENTITY_ID_COLUMN,
Database.PLAYER_ID_COLUMN);
private static final String GET_BLOCK_OWNER_QUERY =
String.format("SELECT %1$s FROM %2$s WHERE %3$s=? AND %4$s=? AND %5$s=? AND %6$s=?;",
Database.PLAYER_ID_COLUMN, Database.BLOCK_TABLE, Database.WORLD_COLUMN, Database.X_COLUMN,
Database.Y_COLUMN, Database.Z_COLUMN);
private static final String GET_ENTITY_OWNER_QUERY =
String.format("SELECT %1$s FROM %2$s WHERE %3$s=? AND %4$s=?;", Database.PLAYER_ID_COLUMN,
Database.ENTITY_TABLE, Database.WORLD_COLUMN, Database.ENTITY_ID_COLUMN);
private static final String UNOWN_BLOCK_QUERY = String.format(
"DELETE FROM %1$s WHERE %2$s=? AND %3$s=? AND %4$s=? AND %5$s=?;", Database.BLOCK_TABLE,
Database.WORLD_COLUMN, Database.X_COLUMN, Database.Y_COLUMN, Database.Z_COLUMN);
private static final String UNOWN_ENTITY_QUERY =
String.format("DELETE FROM %1$s WHERE %2$s=? AND %3$s=?;", Database.ENTITY_TABLE,
Database.WORLD_COLUMN, Database.ENTITY_ID_COLUMN);
private static final String OWN_BLOCK_QUERY = String.format(
"INSERT INTO %1$s(%2$s, %3$s, %4$s, %5$s, %6$s) VALUES(?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE %2$s=VALUES(%2$s), %3$s=VALUES(%3$s), %4$s=VALUES(%4$s), %5$s=VALUES(%5$s), %6$s=VALUES(%6$s);",
Database.BLOCK_TABLE, Database.WORLD_COLUMN, Database.X_COLUMN, Database.Y_COLUMN,
Database.Z_COLUMN, Database.PLAYER_ID_COLUMN);
private static final String OWN_ENTITY_QUERY = String.format(
"INSERT INTO %1$s(%2$s, %3$s, %4$s) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE %2$s=VALUES(%2$s), %3$s=VALUES(%3$s), %4$s=VALUES(%4$s);",
Database.ENTITY_TABLE, Database.WORLD_COLUMN, Database.ENTITY_ID_COLUMN,
Database.PLAYER_ID_COLUMN);
private static final String DROP_USER_BLOCK_QUERY = String
.format("DELETE FROM %1$s WHERE %2$s=?;", Database.BLOCK_TABLE, Database.PLAYER_ID_COLUMN);
private static final String DROP_USER_ENTITY_QUERY = String
.format("DELETE FROM %1$s WHERE %2$s=?;", Database.ENTITY_TABLE, Database.PLAYER_ID_COLUMN);
public static class Builder {
private final Output output;
private File pluginFolder = new File("plugins/BlockOwn");
private String host = "localhost";
private int port = 3306;
private String databaseName = "BlockOwn";
private String userName = null;
private String password = null;
public Builder(Output output) {
if (output == null) {
throw new NullArgumentException("output");
}
this.output = output;
}
public Builder pluginFolder(File pluginFolder) {
if (pluginFolder == null) {
throw new NullArgumentException("pluginFolder");
}
this.pluginFolder = pluginFolder;
return this;
}
public Builder host(String host) {
if (host == null) {
throw new NullArgumentException("host");
}
this.host = host;
return this;
}
public Builder port(int port) {
this.port = port;
return this;
}
public Builder database(String databaseName) {
if (databaseName == null) {
throw new NullArgumentException("databaseName");
}
this.databaseName = databaseName;
return this;
}
public Builder user(String userName) {
if (userName == null) {
throw new NullArgumentException("userName");
}
this.userName = userName;
return this;
}
public Builder password(String password) {
if (password == null) {
throw new NullArgumentException("password");
}
this.password = password;
return this;
}
public MySqlDatabase build() throws ClassNotFoundException, SQLException {
if (host == null) {
throw new NullArgumentException("host");
}
return new MySqlDatabase(output, pluginFolder, host, port, databaseName, userName, password);
}
}
/**
* Instantiates a new MySql database.
*
* @param output the output
* @param pluginFolder the plugin folder
* @param host the host
* @param port the port
* @param databaseName the database name
* @param username the username
* @param password the password
* @throws SQLException if connection fails
* @throws ClassNotFoundException if mysql driver class is missing
*/
private MySqlDatabase(Output output, File pluginFolder, String host, int port,
String databaseName, String username, String password)
throws SQLException, ClassNotFoundException {
super(output, pluginFolder);
connectionPool = connect(host, port, databaseName, username, password);
createTables();
}
private HikariDataSource connect(String host, int port, String databaseName, String username,
String password) throws SQLException {
HikariConfig config = new HikariConfig();
config.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
config.setUsername(username);
config.setPassword(password);
config.addDataSourceProperty("url", "jdbc:mysql://" + host + ":" + port + "/" + databaseName);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
return new HikariDataSource(config);
}
@Override
PreparedStatement[] createCreateTablesStatements() throws SQLException {
Connection connection = getConnection();
PreparedStatement[] stmnts = {connection.prepareStatement(CREATE_BLOCK_TABLE_QUERY),
connection.prepareStatement(CREATE_ENTITY_TABLE_QUERY)};
return stmnts;
}
@Override
PreparedStatement createGetOwnerStatement(Ownable ownable) throws SQLException {
PreparedStatement stmnt;
if (ownable instanceof OwnedBlock) {
OwnedBlock block = (OwnedBlock) ownable;
stmnt = getConnection().prepareStatement(GET_BLOCK_OWNER_QUERY);
stmnt.setString(1, block.getWorldName());
stmnt.setInt(2, block.getX());
stmnt.setInt(3, block.getY());
stmnt.setInt(4, block.getZ());
} else if (ownable instanceof OwnedEntity) {
OwnedEntity entity = (OwnedEntity) ownable;
stmnt = getConnection().prepareStatement(GET_ENTITY_OWNER_QUERY);
stmnt.setString(1, entity.getWorldName());
stmnt.setString(2, entity.getUniqueId().toString());
} else {
throw new IllegalArgumentException("Invalid Ownable type");
}
return stmnt;
}
@Override
PreparedStatement createSetOwnerStatement(DatabaseAction databaseAction) throws SQLException {
PreparedStatement stmnt;
if (databaseAction.getActionType() == DatabaseAction.Type.UNOWN) {
if (databaseAction.getOwnable() instanceof OwnedBlock) {
OwnedBlock block = (OwnedBlock) databaseAction.getOwnable();
stmnt = getConnection().prepareStatement(UNOWN_BLOCK_QUERY);
stmnt.setString(1, block.getWorldName());
stmnt.setInt(2, block.getX());
stmnt.setInt(3, block.getY());
stmnt.setInt(4, block.getZ());
} else if (databaseAction.getOwnable() instanceof OwnedEntity) {
OwnedEntity entity = (OwnedEntity) databaseAction.getOwnable();
stmnt = getConnection().prepareStatement(UNOWN_ENTITY_QUERY);
stmnt.setString(1, entity.getWorldName());
stmnt.setString(2, entity.getUniqueId().toString());
} else {
throw new IllegalArgumentException("Invalid Ownable type");
}
} else if (databaseAction.getActionType() == DatabaseAction.Type.OWN) {
if (databaseAction.getOwnable() instanceof OwnedBlock) {
OwnedBlock block = (OwnedBlock) databaseAction.getOwnable();
stmnt = getConnection().prepareStatement(OWN_BLOCK_QUERY);
stmnt.setString(1, block.getWorldName());
stmnt.setInt(2, block.getX());
stmnt.setInt(3, block.getY());
stmnt.setInt(4, block.getZ());
stmnt.setString(5, databaseAction.getUser().getUniqueId().toString());
} else if (databaseAction.getOwnable() instanceof OwnedEntity) {
OwnedEntity entity = (OwnedEntity) databaseAction.getOwnable();
stmnt = getConnection().prepareStatement(OWN_ENTITY_QUERY);
stmnt.setString(1, entity.getWorldName());
stmnt.setString(2, entity.getUniqueId().toString());
stmnt.setString(3, databaseAction.getUser().getUniqueId().toString());
} else {
throw new IllegalArgumentException("Invalid Ownable type");
}
} else {
// Should never happen
getOutput().printException(new IllegalArgumentException("Invalid DatabaseActionType"));
return null;
}
return stmnt;
}
@Override
PreparedStatement[] createDropUserStatements(User user) throws SQLException {
Connection connection = getConnection();
PreparedStatement stmnt1 = connection.prepareStatement(DROP_USER_BLOCK_QUERY);
stmnt1.setString(1, user.getUniqueId().toString());
PreparedStatement stmnt2 = connection.prepareStatement(DROP_USER_ENTITY_QUERY);
stmnt2.setString(1, user.getUniqueId().toString());
return new PreparedStatement[]{stmnt1, stmnt2};
}
}