diff --git a/pom.xml b/pom.xml index 38f3e79..f21b5b1 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,12 @@ mongo-java-driver 2.10.1 + + org.apache.tomcat + tomcat-jdbc + 7.0.52 + compile + clean package install @@ -79,6 +85,8 @@ org.mongodb:mongo-java-driver + org.apache.tomcat:tomcat-jdbc + org.apache.tomcat:tomcat-juli diff --git a/src/org/melonbrew/fe/database/Database.java b/src/org/melonbrew/fe/database/Database.java index 43aa1d3..e5b68a2 100644 --- a/src/org/melonbrew/fe/database/Database.java +++ b/src/org/melonbrew/fe/database/Database.java @@ -10,13 +10,15 @@ public abstract class Database { private final Fe plugin; - private final Set cachedAccounts; + private final HashMap cachedAccountsUUID; + private final HashMap cachedAccountsUsername; protected boolean cacheAccounts; public Database(Fe plugin) { this.plugin = plugin; - this.cachedAccounts = new HashSet(); + this.cachedAccountsUUID = new HashMap(); + this.cachedAccountsUsername = new HashMap(); } public boolean init() { @@ -26,38 +28,27 @@ public boolean init() { } public List getTopAccounts(int size) { - List topAccounts = loadTopAccounts(size * 2); - - if (!cachedAccounts.isEmpty()) { - for (Account account : cachedAccounts) { + List topAccounts = this.loadTopAccounts(size * 2); + if (!this.cachedAccountsUUID.isEmpty()) { + final Account lowest = topAccounts.get(topAccounts.size() - 1); + final List cachedTopAccounts = new ArrayList(); + for (final Account account : this.cachedAccountsUUID.values()) { topAccounts.remove(account); - } - - List cachedTopAccounts = new ArrayList(cachedAccounts); - - Collections.sort(cachedTopAccounts, new Comparator() { - public int compare(Account account1, Account account2) { - return (int) (account2.getMoney() - account1.getMoney()); + if (lowest.getMoney() <= account.getMoney()) { + cachedTopAccounts.add(account); } - }); - - if (cachedAccounts.size() > size) { - cachedTopAccounts = cachedTopAccounts.subList(0, size); } - topAccounts.addAll(cachedTopAccounts); } - Collections.sort(topAccounts, new Comparator() { - public int compare(Account account1, Account account2) { - return (int) (account2.getMoney() - account1.getMoney()); + @Override + public int compare(final Account account1, final Account account2) { + return (int)(account2.getMoney() - account1.getMoney()); } }); - if (topAccounts.size() > size) { topAccounts = topAccounts.subList(0, size); } - return topAccounts; } @@ -82,9 +73,8 @@ public void removeAccount(String name, String uuid) { public abstract void clean(); public void removeAllAccounts() { - for (Account account : new HashSet(cachedAccounts)) { - cachedAccounts.remove(account); - } + cachedAccountsUUID.clear(); + cachedAccountsUsername.clear(); } protected boolean convertToUUID() { @@ -146,15 +136,11 @@ protected boolean convertToUUID() { } public void close() { - Iterator iterator = cachedAccounts.iterator(); - - while (iterator.hasNext()) { - Account account = iterator.next(); - + for (final Account account : this.cachedAccountsUUID.values()) { account.save(account.getMoney()); - - iterator.remove(); } + this.cachedAccountsUUID.clear(); + this.cachedAccountsUsername.clear(); } public abstract String getName(); @@ -202,7 +188,8 @@ private Account createAndAddAccount(String name, String uuid, double money) { Player player = plugin.getServer().getPlayerExact(name); if (player != null) { - cachedAccounts.add(account); + this.cachedAccountsUsername.put(name, account); + this.cachedAccountsUUID.put(UUID.fromString(uuid), account); } } @@ -218,17 +205,16 @@ public boolean cacheAccounts() { } public Account getCachedAccount(String name, String uuid) { - for (Account account : cachedAccounts) { - if (account.getName().equals(name)) { - return account; - } + if (uuid != null) { + return this.cachedAccountsUUID.get(UUID.fromString(uuid)); } - - return null; + return this.cachedAccountsUsername.get(name); } public boolean removeCachedAccount(Account account) { - return cachedAccounts.remove(account); + this.cachedAccountsUUID.remove(UUID.fromString(account.getUUID())); + this.cachedAccountsUsername.remove(account.getName()); + return true; } public abstract int getVersion(); diff --git a/src/org/melonbrew/fe/database/databases/MySQLDB.java b/src/org/melonbrew/fe/database/databases/MySQLDB.java index 1fe36af..be07321 100644 --- a/src/org/melonbrew/fe/database/databases/MySQLDB.java +++ b/src/org/melonbrew/fe/database/databases/MySQLDB.java @@ -1,36 +1,56 @@ package org.melonbrew.fe.database.databases; +import org.apache.tomcat.jdbc.pool.DataSource; +import org.apache.tomcat.jdbc.pool.PoolProperties; import org.bukkit.configuration.ConfigurationSection; import org.melonbrew.fe.Fe; +import org.melonbrew.fe.database.Account; +import org.melonbrew.fe.database.Database; import java.sql.Connection; -import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class MySQLDB extends Database { + private final Fe plugin; + private DataSource pool; + private String table; + private String usernameField; + private String balanceField; + private String uuidField; -public class MySQLDB extends SQLDB { public MySQLDB(Fe plugin) { - super(plugin, true); + super(plugin); + this.plugin = plugin; } - protected Connection getNewConnection() { - ConfigurationSection config = getConfigSection(); + public void getConfigDefaults(ConfigurationSection section) { + section.addDefault("host", "localhost"); - setAccountTable(config.getString("tables.accounts")); + section.addDefault("port", 3306); - setAccountsColumnUser(config.getString("columns.accounts.username")); + section.addDefault("user", "root"); - setAccountsColumnMoney(config.getString("columns.accounts.money")); + section.addDefault("password", "minecraft"); - setAccountsColumnUUID(config.getString("columns.accounts.uuid")); + section.addDefault("database", "Fe"); - try { - Class.forName("com.mysql.jdbc.Driver"); + ConfigurationSection tables = getSection(section, "tables"); - String url = "jdbc:mysql://" + config.getString("host") + ":" + config.getString("port") + "/" + config.getString("database"); + tables.addDefault("accounts", "fe_accounts"); - return DriverManager.getConnection(url, config.getString("user"), config.getString("password")); - } catch (Exception e) { - return null; - } + ConfigurationSection columns = getSection(section, "columns"); + + ConfigurationSection columnsAccounts = getSection(columns, "accounts"); + + columnsAccounts.addDefault("username", "name"); + + columnsAccounts.addDefault("money", "money"); + + columnsAccounts.addDefault("uuid", "uuid"); } private ConfigurationSection getSection(ConfigurationSection parent, String childName) { @@ -43,33 +63,253 @@ private ConfigurationSection getSection(ConfigurationSection parent, String chil return child; } - public void getConfigDefaults(ConfigurationSection section) { - section.addDefault("host", "localhost"); + public boolean init() { + ConfigurationSection config = getConfigSection(); + String connectionString = "jdbc:mysql://" + config.getString("host") + ":" + config.getString("port") + "/" + config.getString("database"); - section.addDefault("port", 3306); + try { + // Force driver to load if not yet loaded + Class.forName("com.mysql.jdbc.Driver"); + } + catch (ClassNotFoundException e) { + e.printStackTrace(); + return false; + } - section.addDefault("user", "root"); + table = config.getString("tables.accounts"); - section.addDefault("password", "minecraft"); + usernameField = config.getString("columns.accounts.username"); - section.addDefault("database", "Fe"); + balanceField = config.getString("columns.accounts.money"); - ConfigurationSection tables = getSection(section, "tables"); + uuidField = config.getString("columns.accounts.uuid"); + + PoolProperties poolProperties = new PoolProperties(); + poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); + poolProperties.setUrl(connectionString); + poolProperties.setUsername(config.getString("user")); + poolProperties.setPassword(config.getString("password")); + poolProperties.setMaxIdle(5); + poolProperties.setMaxActive(5); + poolProperties.setInitialSize(0); + poolProperties.setMaxWait(-1); + poolProperties.setRemoveAbandoned(true); + poolProperties.setRemoveAbandonedTimeout(60); + poolProperties.setTestOnBorrow(true); + poolProperties.setValidationQuery("SELECT 1"); + poolProperties.setValidationInterval(30000); + pool = new DataSource(poolProperties); + Connection connection = null; + PreparedStatement statement = null; + ResultSet rs = null; + try { + connection = pool.getConnection(); + statement = connection.prepareStatement("SHOW TABLES LIKE '" + table + "'"); + rs = statement.executeQuery(); - tables.addDefault("accounts", "fe_accounts"); + if (rs.next()) { + return true; + } - ConfigurationSection columns = getSection(section, "columns"); + rs.close(); + statement.close(); - ConfigurationSection columnsAccounts = getSection(columns, "accounts"); + statement = connection.prepareStatement("CREATE TABLE IF NOT EXISTS " + table + " (" + usernameField + " varchar(64) NOT NULL, " + uuidField + " varchar(36) PRIMARY KEY, " + balanceField + " double NOT NULL)"); + statement.executeUpdate(); + return true; + } catch (SQLException e) { + e.printStackTrace(); + } finally { + tryClose(rs); + tryClose(statement); + tryClose(connection); + } + return false; + } - columnsAccounts.addDefault("username", "name"); + private void tryClose(AutoCloseable closeable) { + try { + closeable.close(); + } catch (Exception e) { + } + } - columnsAccounts.addDefault("money", "money"); + public void close() { + super.close(); + pool.close(true); + } - columnsAccounts.addDefault("uuid", "uuid"); + public List loadTopAccounts(int size) { + List topAccounts = new ArrayList(); + + Connection connection = null; + PreparedStatement statement = null; + ResultSet rs = null; + try { + connection = pool.getConnection(); + statement = connection.prepareStatement("SELECT " + usernameField + ", " + uuidField + ", " + balanceField + " FROM " + table + " ORDER BY " + balanceField + " DESC limit " + size); + rs = statement.executeQuery(); + while (rs.next()) { + Account account = new Account(plugin, rs.getString(1), rs.getString(2), this); + + account.setMoney(rs.getDouble(3)); + + topAccounts.add(account); + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + tryClose(rs); + tryClose(statement); + tryClose(connection); + } + + return topAccounts; + } + + public List getAccounts() { + List accounts = new ArrayList(); + + Connection connection = null; + PreparedStatement statement = null; + ResultSet rs = null; + try { + connection = pool.getConnection(); + statement = connection.prepareStatement("SELECT " + usernameField + ", " + uuidField + ", " + balanceField + " from " + table + ""); + rs = statement.executeQuery(); + while (rs.next()) { + Account account = new Account(plugin, rs.getString(1), rs.getString(2), this); + + account.setMoney(rs.getDouble(3)); + + accounts.add(account); + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + tryClose(rs); + tryClose(statement); + tryClose(connection); + } + + return accounts; + } + + public Double loadAccountMoney(String name, String uuid) { + Connection connection = null; + PreparedStatement statement = null; + ResultSet rs = null; + try { + connection = pool.getConnection(); + statement = connection.prepareStatement("SELECT " + balanceField + " from " + table + " WHERE UPPER(" + uuidField + ") = UPPER(?) OR (? IS NULL AND UPPER(" + usernameField + ") = UPPER(?))"); + statement.setString(1, uuid); + statement.setString(2, uuid); + statement.setString(3, name); + rs = statement.executeQuery(); + + if (rs.next()) { + return rs.getDouble(1); + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + tryClose(rs); + tryClose(statement); + tryClose(connection); + } + return null; + } + + public void removeAccount(String name, String uuid) { + super.removeAccount(name, uuid); + + Connection connection = null; + PreparedStatement statement = null; + try { + connection = pool.getConnection(); + statement = connection.prepareStatement("DELETE FROM " + table + " WHERE UPPER(" + uuidField + ") = UPPER(?) OR (? IS NULL AND UPPER(" + usernameField + ") = UPPER(?))"); + statement.setString(1, uuid); + statement.setString(2, uuid); + statement.setString(3, name); + + statement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + tryClose(statement); + tryClose(connection); + } + } + + protected void saveAccount(String name, String uuid, double money) { + Connection connection = null; + PreparedStatement statement = null; + try { + connection = pool.getConnection(); + statement = connection.prepareStatement("UPDATE " + table + " SET " + balanceField + "=?, " + usernameField + "=? WHERE UPPER(" + uuidField + ") = UPPER(?) OR (? IS NULL AND UPPER(" + usernameField + ") = UPPER(?))"); + + statement.setDouble(1, money); + statement.setString(2, name); + statement.setString(3, uuid); + statement.setString(4, uuid); + statement.setString(5, name); + + if (statement.executeUpdate() == 0) { + statement.close(); + statement = connection.prepareStatement("INSERT INTO " + table + " (" + usernameField + ", " + uuidField + ", " + balanceField + ") VALUES (?, ?, ?)"); + statement.setString(1, name); + statement.setString(2, uuid); + statement.setDouble(3, money); + statement.executeUpdate(); + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + tryClose(statement); + tryClose(connection); + } + } + + public void clean() { + Connection connection = null; + PreparedStatement statement = null; + try { + connection = pool.getConnection(); + statement = connection.prepareStatement("DELETE FROM " + table + " WHERE " + balanceField + " = " + plugin.getAPI().getDefaultHoldings()); + statement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + tryClose(statement); + tryClose(connection); + } + } + + public void removeAllAccounts() { + super.removeAllAccounts(); + Connection connection = null; + PreparedStatement statement = null; + try { + connection = pool.getConnection(); + statement = connection.prepareStatement("DELETE FROM " + table); + statement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + tryClose(statement); + tryClose(connection); + } } public String getName() { return "MySQL"; } + + @Override + public int getVersion() { + return 2; + } + + @Override + public void setVersion(int version) { } }