From 8f75f9f90d127527b6b7fb138aefa6b0adbf6913 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 1 Jul 2016 14:28:31 +0200 Subject: [PATCH] Check database connection before accessing it This hopefully fixes #7 --- config.yml | 4 + src/de/epiceric/shopchest/config/Config.java | 5 + .../listeners/ShopInteractListener.java | 10 +- src/de/epiceric/shopchest/sql/Database.java | 112 ++++++++++++++---- .../epiceric/shopchest/utils/ShopUtils.java | 8 +- 5 files changed, 112 insertions(+), 27 deletions(-) diff --git a/config.yml b/config.yml index f7996e4..6299211 100644 --- a/config.yml +++ b/config.yml @@ -60,6 +60,10 @@ database: # Either use 'SQLite' or 'MySQL'. Otherwise you will break the plugin! type: "SQLite" + # Set the amount of attempts, ShopChest tries to reconnect to the database, + # when the connection is lost, until giving up. + reconnect-attemps: 5 + # If the specified type is 'MySQL', here you configure the... # (You can leave this empty if you're using SQLite) mysql: diff --git a/src/de/epiceric/shopchest/config/Config.java b/src/de/epiceric/shopchest/config/Config.java index 34e8d16..7022b51 100644 --- a/src/de/epiceric/shopchest/config/Config.java +++ b/src/de/epiceric/shopchest/config/Config.java @@ -32,6 +32,11 @@ public class Config { /** The database type used for ShopChest. **/ public static Database.DatabaseType database_type = Database.DatabaseType.valueOf(plugin.getConfig().getString("database.type")); + /** + * The amount of attempts, ShopChest tries to reconnect to the database, when the connection is lost, until giving up + **/ + public static int database_reconnect_attempts = plugin.getConfig().getInt("database.reconnect-attempts"); + /** *

The minimum prices for certain items

* This returns a key set, which contains e.g "STONE", "STONE:1", of the minimum-prices section in ShopChest's config. diff --git a/src/de/epiceric/shopchest/listeners/ShopInteractListener.java b/src/de/epiceric/shopchest/listeners/ShopInteractListener.java index bb293fc..9118da5 100644 --- a/src/de/epiceric/shopchest/listeners/ShopInteractListener.java +++ b/src/de/epiceric/shopchest/listeners/ShopInteractListener.java @@ -3,6 +3,7 @@ package de.epiceric.shopchest.listeners; import com.griefcraft.lwc.LWC; import com.griefcraft.model.Protection; import de.epiceric.shopchest.ShopChest; +import de.epiceric.shopchest.config.Config; import de.epiceric.shopchest.config.Regex; import de.epiceric.shopchest.language.LanguageUtils; import de.epiceric.shopchest.language.LocalizedMessage; @@ -234,7 +235,14 @@ public class ShopInteractListener implements Listener { * @param shopType Type of the shop */ private void create(Player executor, Location location, ItemStack product, double buyPrice, double sellPrice, ShopType shopType) { - Shop shop = new Shop(database.getNextFreeID(), plugin, executor, product, location, buyPrice, sellPrice, shopType); + int id = database.getNextFreeID(Config.database_reconnect_attempts); + + if (id == 0) { + executor.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.ERROR_OCCURRED, new LocalizedMessage.ReplacedRegex(Regex.ERROR, "Could not connect to database"))); + return; + } + + Shop shop = new Shop(id, plugin, executor, product, location, buyPrice, sellPrice, shopType); ShopUtils.addShop(shop, true); executor.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.SHOP_CREATED)); diff --git a/src/de/epiceric/shopchest/sql/Database.java b/src/de/epiceric/shopchest/sql/Database.java index ffa4b67..24af74e 100644 --- a/src/de/epiceric/shopchest/sql/Database.java +++ b/src/de/epiceric/shopchest/sql/Database.java @@ -1,6 +1,7 @@ package de.epiceric.shopchest.sql; import de.epiceric.shopchest.ShopChest; +import de.epiceric.shopchest.config.Config; import de.epiceric.shopchest.shop.Shop; import de.epiceric.shopchest.shop.Shop.ShopType; import de.epiceric.shopchest.utils.ShopUtils; @@ -19,6 +20,8 @@ public abstract class Database { public ShopChest plugin; public Connection connection; + private int attempts = Config.database_reconnect_attempts; + public Database(ShopChest plugin) { this.plugin = plugin; initialize(); @@ -65,14 +68,23 @@ public abstract class Database { } /** + * @param reconnectAttempts Attempts to reconnect to the database if not connected * @return Lowest possible ID which is not used (> 0) */ - public int getNextFreeID() { - for (int i = 1; i < getHighestID() + 1; i++) { - if (get(i, ShopInfo.X) == null) { + public int getNextFreeID(int reconnectAttempts) { + if (!isConnected()) { + if (reconnectAttempts > 0) { + connection = getConnection(); + plugin.getLogger().info("Reconnecting to database (" + reconnectAttempts + ") ..."); + return getNextFreeID(reconnectAttempts - 1); + } else return 0; + } + + for (int i = 1; i < getHighestID(attempts) + 1; i++) { + if (get(i, ShopInfo.X, attempts) == null) { return i; } else { - if (i == getHighestID()) { + if (i == getHighestID(attempts)) { return i + 1; } } @@ -84,7 +96,15 @@ public abstract class Database { /** * @return Highest ID which is used */ - public int getHighestID() { + public int getHighestID(int reconnectAttempts) { + if (!isConnected()) { + if (reconnectAttempts > 0) { + connection = getConnection(); + plugin.getLogger().info("Reconnecting to database (" + reconnectAttempts + ") ..."); + return getHighestID(reconnectAttempts - 1); + } else return 0; + } + PreparedStatement ps = null; ResultSet rs = null; @@ -116,7 +136,16 @@ public abstract class Database { * * @param shop Shop to remove */ - public void removeShop(Shop shop) { + public void removeShop(Shop shop, int reconnectAttempts) { + if (!isConnected()) { + if (reconnectAttempts > 0) { + connection = getConnection(); + plugin.getLogger().info("Reconnecting to database (" + reconnectAttempts + ") ..."); + removeShop(shop, reconnectAttempts - 1); + return; + } else return; + } + PreparedStatement ps = null; try { @@ -135,7 +164,15 @@ public abstract class Database { * @param shopInfo What to get * @return Value you wanted to get. This needs to be casted to the right type! */ - public Object get(int id, ShopInfo shopInfo) { + public Object get(int id, ShopInfo shopInfo, int reconnectAttempts) { + if (!isConnected()) { + if (reconnectAttempts > 0) { + connection = getConnection(); + plugin.getLogger().info("Reconnecting to database (" + reconnectAttempts + ") ..."); + return get(id, shopInfo, reconnectAttempts - 1); + } else return null; + } + PreparedStatement ps = null; ResultSet rs = null; @@ -148,17 +185,17 @@ public abstract class Database { switch (shopInfo) { case SHOP: - Shop shop = ShopUtils.getShop((Location) get(id, ShopInfo.LOCATION)); + Shop shop = ShopUtils.getShop((Location) get(id, ShopInfo.LOCATION, attempts)); if (shop != null) return shop; else { return new Shop(id, plugin, - (OfflinePlayer) get(id, ShopInfo.VENDOR), - (ItemStack) get(id, ShopInfo.PRODUCT), - (Location) get(id, ShopInfo.LOCATION), - (double) get(id, ShopInfo.BUYPRICE), - (double) get(id, ShopInfo.SELLPRICE), - (ShopType) get(id, ShopInfo.SHOPTYPE)); + (OfflinePlayer) get(id, ShopInfo.VENDOR, attempts), + (ItemStack) get(id, ShopInfo.PRODUCT, attempts), + (Location) get(id, ShopInfo.LOCATION, attempts), + (double) get(id, ShopInfo.BUYPRICE, attempts), + (double) get(id, ShopInfo.SELLPRICE, attempts), + (ShopType) get(id, ShopInfo.SHOPTYPE, attempts)); } case VENDOR: return Bukkit.getOfflinePlayer(UUID.fromString(rs.getString("vendor"))); @@ -173,7 +210,7 @@ public abstract class Database { case Z: return rs.getInt("z"); case LOCATION: - return new Location((World) get(id, ShopInfo.WORLD), (int) get(id, ShopInfo.X), (int) get(id, ShopInfo.Y), (int) get(id, ShopInfo.Z)); + return new Location((World) get(id, ShopInfo.WORLD, attempts), (int) get(id, ShopInfo.X, attempts), (int) get(id, ShopInfo.Y, attempts), (int) get(id, ShopInfo.Z, attempts)); case BUYPRICE: return rs.getDouble("buyprice"); case SELLPRICE: @@ -184,14 +221,14 @@ public abstract class Database { if (shoptype.equals("INFINITE")) { Shop newShop = new Shop(id, plugin, - (OfflinePlayer) get(id, ShopInfo.VENDOR), - (ItemStack) get(id, ShopInfo.PRODUCT), - (Location) get(id, ShopInfo.LOCATION), - (double) get(id, ShopInfo.BUYPRICE), - (double) get(id, ShopInfo.SELLPRICE), + (OfflinePlayer) get(id, ShopInfo.VENDOR, attempts), + (ItemStack) get(id, ShopInfo.PRODUCT, attempts), + (Location) get(id, ShopInfo.LOCATION, attempts), + (double) get(id, ShopInfo.BUYPRICE, attempts), + (double) get(id, ShopInfo.SELLPRICE, attempts), ShopType.ADMIN); - addShop(newShop); + addShop(newShop, attempts); return ShopType.ADMIN; } @@ -213,7 +250,16 @@ public abstract class Database { * Adds a shop to the database * @param shop Shop to add */ - public void addShop(Shop shop) { + public void addShop(Shop shop, int reconnectAttempts) { + if (!isConnected()) { + if (reconnectAttempts > 0) { + connection = getConnection(); + plugin.getLogger().info("Reconnecting to database (" + reconnectAttempts + ") ..."); + addShop(shop, reconnectAttempts - 1); + return; + } else return; + } + PreparedStatement ps = null; try { @@ -238,6 +284,28 @@ public abstract class Database { } } + /** + * @return Whether ShopChest is connected to the database + */ + private boolean isConnected() { + PreparedStatement ps = null; + ResultSet rs = null; + + boolean connected = false; + + try { + ps = connection.prepareStatement("SELECT * FROM shop_list"); + rs = ps.executeQuery(); + connected = true; + } catch (SQLException e) { + connected = false; + } finally { + close(ps, rs); + } + + return connected; + } + /** * Closes a {@link PreparedStatement} and a {@link ResultSet} * @param ps {@link PreparedStatement} to close diff --git a/src/de/epiceric/shopchest/utils/ShopUtils.java b/src/de/epiceric/shopchest/utils/ShopUtils.java index a431dea..9719cc2 100644 --- a/src/de/epiceric/shopchest/utils/ShopUtils.java +++ b/src/de/epiceric/shopchest/utils/ShopUtils.java @@ -81,7 +81,7 @@ public class ShopUtils { } if (addToDatabase) - plugin.getShopDatabase().addShop(shop); + plugin.getShopDatabase().addShop(shop, Config.database_reconnect_attempts); } @@ -108,7 +108,7 @@ public class ShopUtils { shop.removeHologram(); if (removeFromDatabase) - plugin.getShopDatabase().removeShop(shop); + plugin.getShopDatabase().removeShop(shop, Config.database_reconnect_attempts); } /** @@ -212,10 +212,10 @@ public class ShopUtils { } int count = 0; - for (int id = 1; id < plugin.getShopDatabase().getHighestID() + 1; id++) { + for (int id = 1; id < plugin.getShopDatabase().getHighestID(Config.database_reconnect_attempts) + 1; id++) { try { - Shop shop = (Shop) plugin.getShopDatabase().get(id, Database.ShopInfo.SHOP); + Shop shop = (Shop) plugin.getShopDatabase().get(id, Database.ShopInfo.SHOP, Config.database_reconnect_attempts); ShopUtils.addShop(shop, false); } catch (NullPointerException e) { continue;