Improved database interaction

This commit is contained in:
Eric 2017-02-09 21:51:39 +01:00
parent 7b3dac61ac
commit 1e38edc7a0
5 changed files with 187 additions and 240 deletions

View File

@ -473,7 +473,7 @@ class ShopCommand implements CommandExecutor {
plugin.debug(p.getName() + " can pay the creation price"); plugin.debug(p.getName() + " can pay the creation price");
ShopPreCreateEvent event = new ShopPreCreateEvent(p, Shop.createImaginaryShop(p, itemStack, null, buyPrice, sellPrice, shopType)); ShopPreCreateEvent event = new ShopPreCreateEvent(p, new Shop(plugin, p, itemStack, null, buyPrice, sellPrice, shopType));
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) { if (!event.isCancelled()) {

View File

@ -17,7 +17,10 @@ import de.epiceric.shopchest.nms.Hologram;
import de.epiceric.shopchest.shop.Shop; import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.shop.Shop.ShopType; import de.epiceric.shopchest.shop.Shop.ShopType;
import de.epiceric.shopchest.sql.Database; import de.epiceric.shopchest.sql.Database;
import de.epiceric.shopchest.utils.*; import de.epiceric.shopchest.utils.ClickType;
import de.epiceric.shopchest.utils.Permissions;
import de.epiceric.shopchest.utils.ShopUtils;
import de.epiceric.shopchest.utils.Utils;
import de.epiceric.shopchest.worldguard.ShopFlag; import de.epiceric.shopchest.worldguard.ShopFlag;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.Economy;
@ -447,19 +450,14 @@ public class ShopInteractListener implements Listener {
private void create(final Player executor, final Location location, final ItemStack product, final double buyPrice, final double sellPrice, final ShopType shopType) { private void create(final Player executor, final Location location, final ItemStack product, final double buyPrice, final double sellPrice, final ShopType shopType) {
plugin.debug(executor.getName() + " is creating new shop..."); plugin.debug(executor.getName() + " is creating new shop...");
database.getNextFreeID(new Callback(plugin) {
@Override
public void onResult(Object result) {
if (result instanceof Integer) {
int id = (int) result;
double creationPrice = (shopType == ShopType.NORMAL) ? config.shop_creation_price_normal : config.shop_creation_price_admin; double creationPrice = (shopType == ShopType.NORMAL) ? config.shop_creation_price_normal : config.shop_creation_price_admin;
Shop shop = new Shop(id, plugin, executor, product, location, buyPrice, sellPrice, shopType); Shop shop = new Shop(plugin, executor, product, location, buyPrice, sellPrice, shopType);
ShopCreateEvent event = new ShopCreateEvent(executor, shop, creationPrice); ShopCreateEvent event = new ShopCreateEvent(executor, shop, creationPrice);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) { if (event.isCancelled()) {
plugin.debug("Create event cancelled (#" + id + ")"); plugin.debug("Create event cancelled");
return; return;
} }
@ -472,8 +470,9 @@ public class ShopInteractListener implements Listener {
shop.create(); shop.create();
plugin.debug("Shop created (#" + id + ")"); plugin.debug("Shop created");
shopUtils.addShop(shop, true); shopUtils.addShop(shop, true);
executor.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.SHOP_CREATED)); executor.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.SHOP_CREATED));
for (Player p : location.getWorld().getPlayers()) { for (Player p : location.getWorld().getPlayers()) {
@ -489,12 +488,6 @@ public class ShopInteractListener implements Listener {
} }
} }
} }
}
@Override
public void onError(Throwable throwable) {}
});
}
/** /**
* Remove a shop * Remove a shop

View File

@ -44,18 +44,14 @@ public class Shop {
this.shopType = shopType; this.shopType = shopType;
} }
private Shop(OfflinePlayer vendor, ItemStack product, Location location, double buyPrice, double sellPrice, ShopType shopType) { public Shop(ShopChest plugin, OfflinePlayer vendor, ItemStack product, Location location, double buyPrice, double sellPrice, ShopType shopType) {
this.id = 0; this(-1, plugin, vendor, product, location, buyPrice, sellPrice, shopType);
this.vendor = vendor;
this.product = product;
this.location = location;
this.buyPrice = buyPrice;
this.sellPrice = sellPrice;
this.shopType = shopType;
} }
public void create() { public boolean create() {
if (created) return; if (created) return false;
plugin.debug("Creating shop (#" + id + ")");
Block b = location.getBlock(); Block b = location.getBlock();
if (b.getType() != Material.CHEST && b.getType() != Material.TRAPPED_CHEST) { if (b.getType() != Material.CHEST && b.getType() != Material.TRAPPED_CHEST) {
@ -64,20 +60,21 @@ public class Shop {
plugin.getLogger().severe(ex.getMessage()); plugin.getLogger().severe(ex.getMessage());
plugin.debug("Failed to create shop (#" + id + ")"); plugin.debug("Failed to create shop (#" + id + ")");
plugin.debug(ex); plugin.debug(ex);
return; return false;
} else if ((b.getRelative(BlockFace.UP).getType() != Material.AIR) && plugin.getShopChestConfig().show_shop_items) { } else if ((b.getRelative(BlockFace.UP).getType() != Material.AIR) && plugin.getShopChestConfig().show_shop_items) {
NotEnoughSpaceException ex = new NotEnoughSpaceException("No space above chest at location: " + b.getX() + "; " + b.getY() + "; " + b.getZ()); NotEnoughSpaceException ex = new NotEnoughSpaceException("No space above chest at location: " + b.getX() + "; " + b.getY() + "; " + b.getZ());
plugin.getShopUtils().removeShop(this, plugin.getShopChestConfig().remove_shop_on_error); plugin.getShopUtils().removeShop(this, plugin.getShopChestConfig().remove_shop_on_error);
plugin.getLogger().severe(ex.getMessage()); plugin.getLogger().severe(ex.getMessage());
plugin.debug("Failed to create shop (#" + id + ")"); plugin.debug("Failed to create shop (#" + id + ")");
plugin.debug(ex); plugin.debug(ex);
return; return false;
} }
if (hologram == null || !hologram.exists()) createHologram(); if (hologram == null || !hologram.exists()) createHologram();
if (item == null) createItem(); if (item == null) createItem();
created = true; created = true;
return true;
} }
/** /**
@ -223,6 +220,23 @@ public class Shop {
hologram = new Hologram(plugin, holoText, holoLocation); hologram = new Hologram(plugin, holoText, holoLocation);
} }
/**
* @return Whether an ID has been assigned to the shop
*/
public boolean hasId() {
return id != -1;
}
/**
* Assign an ID to the shop. <br/>
* Only works for the first time!
*/
public void setId(int id) {
if (this.id == -1) {
this.id = id;
}
}
/** /**
* @return Whether the shop has already been created * @return Whether the shop has already been created
*/ */
@ -307,13 +321,6 @@ public class Shop {
return null; return null;
} }
/**
* @return A shop, which is not really a shop. It's just for "storing" the data (used in some events).
*/
public static Shop createImaginaryShop(OfflinePlayer vendor, ItemStack product, Location location, double buyPrice, double sellPrice, ShopType shopType) {
return new Shop(vendor, product, location, buyPrice, sellPrice, shopType);
}
public enum ShopType { public enum ShopType {
NORMAL, NORMAL,
ADMIN ADMIN

View File

@ -18,6 +18,7 @@ import org.bukkit.scheduler.BukkitRunnable;
import java.sql.*; import java.sql.*;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.UUID; import java.util.UUID;
@ -50,18 +51,17 @@ public abstract class Database {
connection = getConnection(); connection = getConnection();
String queryCreateTableShopList = String queryCreateTableShopList =
"CREATE TABLE IF NOT EXISTS shop_list (" + "CREATE TABLE IF NOT EXISTS shops (" +
"`id` int(11) NOT NULL," + "`id` INTEGER PRIMARY KEY " + (Database.this instanceof SQLite ? "AUTOINCREMENT" : "AUTO_INCREMENT") + "," +
"`vendor` tinytext NOT NULL," + "`vendor` TINYTEXT NOT NULL," +
"`product` text NOT NULL," + "`product` TEXT NOT NULL," +
"`world` tinytext NOT NULL," + "`world` TINYTEXT NOT NULL," +
"`x` int(11) NOT NULL," + "`x` INTEGER NOT NULL," +
"`y` int(11) NOT NULL," + "`y` INTEGER NOT NULL," +
"`z` int(11) NOT NULL," + "`z` INTEGER NOT NULL," +
"`buyprice` float(32) NOT NULL," + "`buyprice` FLOAT NOT NULL," +
"`sellprice` float(32) NOT NULL," + "`sellprice` FLOAT NOT NULL," +
"`shoptype` tinytext NOT NULL," + "`shoptype` TINYTEXT NOT NULL" +
"PRIMARY KEY (`id`)" +
");"; ");";
String queryCreateTableShopLog = String queryCreateTableShopLog =
@ -79,113 +79,68 @@ public abstract class Database {
"`type` TINYTEXT NOT NULL" + "`type` TINYTEXT NOT NULL" +
");"; ");";
// Create table "shop_list" String queryCheckIfTableExists =
(Database.this instanceof SQLite ?
"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'shop_list'" :
"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'shop_list'");
String queryCopyTableShopList = "INSERT INTO shops (vendor,product,world,x,y,z,buyprice,sellprice,shoptype) SELECT vendor,product,world,x,y,z,buyprice,sellprice,shoptype FROM shop_list";
String queryRenameTableShopList = "ALTER TABLE shop_list RENAME TO shop_list_old";
// Create table "shops"
Statement s = connection.createStatement(); Statement s = connection.createStatement();
s.executeUpdate(queryCreateTableShopList); s.executeUpdate(queryCreateTableShopList);
s.close(); s.close();
// Create table "shop_log" // Check if old table "shop_list" exists
Statement s2 = connection.createStatement(); Statement s2 = connection.createStatement();
s2.executeUpdate(queryCreateTableShopLog); ResultSet rs = s2.executeQuery(queryCheckIfTableExists);
s2.close();
// Count entries in table "shop_list" if (rs.next()) {
PreparedStatement ps = connection.prepareStatement("SELECT * FROM shop_list"); plugin.debug("Table 'shop_list' exists: Copying contents...");
ResultSet rs = ps.executeQuery(); // Table exists: Copy contents to new table
PreparedStatement ps = connection.prepareStatement(queryCopyTableShopList);
ps.executeUpdate();
ps.close();
plugin.debug("Renaming table...");
// Rename/Backup old table
PreparedStatement ps2 = connection.prepareStatement(queryRenameTableShopList);
ps2.executeUpdate();
ps2.close();
}
s2.close();
rs.close();
// Create table "shop_log"
Statement s3 = connection.createStatement();
s3.executeUpdate(queryCreateTableShopLog);
s3.close();
// Count entries in table "shops"
PreparedStatement ps = connection.prepareStatement("SELECT * FROM shops");
ResultSet rs2 = ps.executeQuery();
int count = 0; int count = 0;
while (rs.next()) { while (rs2.next()) {
if (rs.getString("vendor") != null) count++; if (rs2.getString("vendor") != null) count++;
} }
plugin.debug("Initialized database with " + count + " entries"); plugin.debug("Initialized database with " + count + " entries");
close(ps, rs); close(ps, rs2);
if (callback != null) callback.callSyncResult(count); if (callback != null) callback.callSyncResult(count);
} catch (SQLException ex) { } catch (SQLException ex) {
if (callback != null) callback.callSyncError(ex); if (callback != null) callback.callSyncError(ex);
plugin.getLogger().severe("Failed to connect to database"); plugin.getLogger().severe("Failed to initialize database");
plugin.debug("Failed to connect to database"); plugin.debug("Failed to initialize database");
plugin.debug(ex); plugin.debug(ex);
} }
} }
}.runTaskAsynchronously(plugin); }.runTaskAsynchronously(plugin);
} }
/**
* @return Lowest possible ID which is not used (> 0)
*/
public void getNextFreeID(final Callback callback) {
getHighestID(new Callback(plugin) {
@Override
public void onResult(Object result) {
if (result instanceof Integer) {
int highestId = (int) result;
for (int i = 1; i <= highestId + 1; i++) {
final int id = i;
isShop(i, new Callback(plugin) {
@Override
public void onResult(Object result) {
if (result instanceof Boolean) {
boolean isShop = (boolean) result;
if (!isShop) {
if (callback != null) callback.callSyncResult(id);
}
}
}
@Override
public void onError(Throwable throwable) {
if (callback != null) callback.callSyncError(throwable);
}
});
}
}
}
@Override
public void onError(Throwable throwable) {
if (callback != null) callback.callSyncError(throwable);
}
});
}
/**
* @return Highest ID which is used
*/
public void getHighestID(final Callback callback) {
new BukkitRunnable() {
@Override
public void run() {
PreparedStatement ps = null;
ResultSet rs = null;
int highestID = 0;
try {
ps = connection.prepareStatement("SELECT * FROM shop_list;");
rs = ps.executeQuery();
while (rs.next()) {
if (rs.getInt("id") > highestID) {
highestID = rs.getInt("id");
}
}
plugin.debug("Highest used ID: " + highestID);
if (callback != null) callback.callSyncResult(highestID);
} catch (SQLException ex) {
if (callback != null) callback.callSyncError(ex);
plugin.debug("Failed to get highest used ID");
plugin.getLogger().severe("Failed to access database");
} finally {
close(ps, rs);
}
}
}.runTaskAsynchronously(plugin);
}
/** /**
* Remove a shop from the database * Remove a shop from the database
* *
@ -198,7 +153,7 @@ public abstract class Database {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
ps = connection.prepareStatement("DELETE FROM shop_list WHERE id = " + shop.getID() + ";"); ps = connection.prepareStatement("DELETE FROM shops WHERE id = " + shop.getID() + ";");
plugin.debug("Removing shop from database (#" + shop.getID() + ")"); plugin.debug("Removing shop from database (#" + shop.getID() + ")");
ps.executeUpdate(); ps.executeUpdate();
if (callback != null) callback.callSyncResult(null); if (callback != null) callback.callSyncResult(null);
@ -226,7 +181,7 @@ public abstract class Database {
ResultSet rs = null; ResultSet rs = null;
try { try {
ps = connection.prepareStatement("SELECT * FROM shop_list WHERE id = " + id + ";"); ps = connection.prepareStatement("SELECT * FROM shops WHERE id = " + id + ";");
rs = ps.executeQuery(); rs = ps.executeQuery();
while (rs.next()) { while (rs.next()) {
@ -250,22 +205,24 @@ public abstract class Database {
} }
/** /**
* @param id ID of the shop * Get all shops from the database
* @return Shop with the given ID
*/ */
public void getShop(final int id, final Callback callback) { public void getShops(final Callback callback) {
new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
ArrayList<Shop> shops = new ArrayList<>();
try { try {
ps = connection.prepareStatement("SELECT * FROM shop_list WHERE id = " + id + ";"); ps = connection.prepareStatement("SELECT * FROM shops");
rs = ps.executeQuery(); rs = ps.executeQuery();
while (rs.next()) { while (rs.next()) {
if (rs.getInt("id") == id) { int id = rs.getInt("id");
plugin.debug("Getting Shop... (#" + id + ")"); plugin.debug("Getting Shop... (#" + id + ")");
String worldName = rs.getString("world"); String worldName = rs.getString("world");
@ -276,11 +233,11 @@ public abstract class Database {
if (world == null) { if (world == null) {
WorldNotFoundException ex = new WorldNotFoundException("Could not find world with name \"" + worldName + "\""); WorldNotFoundException ex = new WorldNotFoundException("Could not find world with name \"" + worldName + "\"");
callback.callSyncError(ex); if (callback != null) callback.callSyncError(ex);
plugin.getLogger().warning(ex.getMessage()); plugin.getLogger().warning(ex.getMessage());
plugin.debug("Failed to get shop (#" + id + ")"); plugin.debug("Failed to get shop (#" + id + ")");
plugin.debug(ex); plugin.debug(ex);
return; continue;
} }
Location location = new Location(world, x, y, z); Location location = new Location(world, x, y, z);
@ -290,7 +247,7 @@ public abstract class Database {
plugin.debug("Shop already exists, returning existing one (#" + id + ")."); plugin.debug("Shop already exists, returning existing one (#" + id + ").");
if (callback != null) callback.callSyncResult(shop); if (callback != null) callback.callSyncResult(shop);
} else { } else {
plugin.debug("Creating new shop... (#" + id + ")"); plugin.debug("Initializing new shop... (#" + id + ")");
OfflinePlayer vendor = Bukkit.getOfflinePlayer(UUID.fromString(rs.getString("vendor"))); OfflinePlayer vendor = Bukkit.getOfflinePlayer(UUID.fromString(rs.getString("vendor")));
ItemStack product = Utils.decode(rs.getString("product")); ItemStack product = Utils.decode(rs.getString("product"));
@ -298,24 +255,21 @@ public abstract class Database {
double sellPrice = rs.getDouble("sellprice"); double sellPrice = rs.getDouble("sellprice");
ShopType shopType = ShopType.valueOf(rs.getString("shoptype")); ShopType shopType = ShopType.valueOf(rs.getString("shoptype"));
if (callback != null) callback.callSyncResult(new Shop(id, plugin, vendor, product, location, buyPrice, sellPrice, shopType)); shops.add(new Shop(id, plugin, vendor, product, location, buyPrice, sellPrice, shopType));
}
return;
} }
} }
plugin.debug("Shop with ID not found, returning null. (#" + id + ")"); if (callback != null) callback.callSyncResult(shops.toArray(new Shop[shops.size()]));
} catch (SQLException ex) { } catch (SQLException ex) {
if (callback != null) callback.callSyncError(ex); if (callback != null) callback.callSyncError(ex);
plugin.getLogger().severe("Failed to access database"); plugin.getLogger().severe("Failed to access database");
plugin.debug("Failed to get shop (#" + id + ")"); plugin.debug("Failed to get shops");
plugin.debug(ex); plugin.debug(ex);
} finally { } finally {
close(ps, rs); close(ps, rs);
} }
if (callback != null) callback.callSyncResult(null);
} }
}.runTaskAsynchronously(plugin); }.runTaskAsynchronously(plugin);
} }
@ -329,23 +283,31 @@ public abstract class Database {
@Override @Override
public void run() { public void run() {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null;
try { try {
ps = connection.prepareStatement("REPLACE INTO shop_list (id,vendor,product,world,x,y,z,buyprice,sellprice,shoptype) VALUES(?,?,?,?,?,?,?,?,?,?)"); ps = connection.prepareStatement("REPLACE INTO shops (vendor,product,world,x,y,z,buyprice,sellprice,shoptype) VALUES(?,?,?,?,?,?,?,?,?)", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, shop.getID()); ps.setString(1, shop.getVendor().getUniqueId().toString());
ps.setString(2, shop.getVendor().getUniqueId().toString()); ps.setString(2, Utils.encode(shop.getProduct()));
ps.setString(3, Utils.encode(shop.getProduct())); ps.setString(3, shop.getLocation().getWorld().getName());
ps.setString(4, shop.getLocation().getWorld().getName()); ps.setInt(4, shop.getLocation().getBlockX());
ps.setInt(5, shop.getLocation().getBlockX()); ps.setInt(5, shop.getLocation().getBlockY());
ps.setInt(6, shop.getLocation().getBlockY()); ps.setInt(6, shop.getLocation().getBlockZ());
ps.setInt(7, shop.getLocation().getBlockZ()); ps.setDouble(7, shop.getBuyPrice());
ps.setDouble(8, shop.getBuyPrice()); ps.setDouble(8, shop.getSellPrice());
ps.setDouble(9, shop.getSellPrice()); ps.setString(9, shop.getShopType().toString());
ps.setString(10, shop.getShopType().toString());
ps.executeUpdate(); ps.executeUpdate();
if (callback != null) callback.callSyncResult(null); int shopId = -1;
rs = ps.getGeneratedKeys();
if (rs.next()) {
shopId = rs.getInt(1);
}
shop.setId(shopId);
if (callback != null) callback.callSyncResult(shopId);
plugin.debug("Adding shop to database (#" + shop.getID() + ")"); plugin.debug("Adding shop to database (#" + shop.getID() + ")");
} catch (SQLException ex) { } catch (SQLException ex) {
if (callback != null) callback.callSyncError(ex); if (callback != null) callback.callSyncError(ex);
@ -353,7 +315,7 @@ public abstract class Database {
plugin.debug("Failed to add shop to database (#" + shop.getID() + ")"); plugin.debug("Failed to add shop to database (#" + shop.getID() + ")");
plugin.debug(ex); plugin.debug(ex);
} finally { } finally {
close(ps, null); close(ps, rs);
} }
} }
}.runTaskAsynchronously(plugin); }.runTaskAsynchronously(plugin);

View File

@ -210,42 +210,27 @@ public class ShopUtils {
plugin.debug("Removed shop (#" + shop.getID() + ")"); plugin.debug("Removed shop (#" + shop.getID() + ")");
} }
plugin.getShopDatabase().getHighestID(new Callback(plugin) { plugin.getShopDatabase().getShops(new Callback(plugin) {
@Override @Override
public void onResult(Object result) { public void onResult(Object result) {
if (result instanceof Integer) { if (result instanceof Shop[]) {
int highestId = (int) result; Shop[] shops = (Shop[]) result;
for (Shop shop : shops) {
int count = 0; if (shop.create()) {
for (int i = 1; i <= highestId; i++) {
final int id = i;
plugin.debug("Trying to add shop. (#" + id + ")");
plugin.getShopDatabase().getShop(id, new Callback(plugin) {
@Override
public void onResult(Object result) {
if (result instanceof Shop) {
Shop shop = (Shop) result;
shop.create();
addShop(shop, false); addShop(shop, false);
} }
} }
if (callback != null) callback.callSyncResult(shops.length);
}
}
@Override @Override
public void onError(Throwable throwable) { public void onError(Throwable throwable) {
plugin.debug("Error while adding shop (#" + id + "):"); callback.callSyncError(throwable);
plugin.debug("Error while adding shops");
plugin.debug(throwable); plugin.debug(throwable);
} }
}); });
count++;
}
if (callback != null) callback.callSyncResult(count);
}
}
});
} }
}); });
} }