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}; } }