Check database connection before accessing it

This hopefully fixes #7
This commit is contained in:
Eric 2016-07-01 14:28:31 +02:00
parent 428d4bf029
commit 8f75f9f90d
5 changed files with 112 additions and 27 deletions

View File

@ -60,6 +60,10 @@ database:
# Either use 'SQLite' or 'MySQL'. Otherwise you will break the plugin! # Either use 'SQLite' or 'MySQL'. Otherwise you will break the plugin!
type: "SQLite" 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... # If the specified type is 'MySQL', here you configure the...
# (You can leave this empty if you're using SQLite) # (You can leave this empty if you're using SQLite)
mysql: mysql:

View File

@ -32,6 +32,11 @@ public class Config {
/** The database type used for ShopChest. **/ /** The database type used for ShopChest. **/
public static Database.DatabaseType database_type = Database.DatabaseType.valueOf(plugin.getConfig().getString("database.type")); 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");
/** /**
* <p>The minimum prices for certain items</p> * <p>The minimum prices for certain items</p>
* This returns a key set, which contains e.g "STONE", "STONE:1", of the <i>minimum-prices</i> section in ShopChest's config. * This returns a key set, which contains e.g "STONE", "STONE:1", of the <i>minimum-prices</i> section in ShopChest's config.

View File

@ -3,6 +3,7 @@ package de.epiceric.shopchest.listeners;
import com.griefcraft.lwc.LWC; import com.griefcraft.lwc.LWC;
import com.griefcraft.model.Protection; import com.griefcraft.model.Protection;
import de.epiceric.shopchest.ShopChest; import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.config.Regex; import de.epiceric.shopchest.config.Regex;
import de.epiceric.shopchest.language.LanguageUtils; import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.language.LocalizedMessage; import de.epiceric.shopchest.language.LocalizedMessage;
@ -234,7 +235,14 @@ public class ShopInteractListener implements Listener {
* @param shopType Type of the shop * @param shopType Type of the shop
*/ */
private void create(Player executor, Location location, ItemStack product, double buyPrice, double sellPrice, ShopType shopType) { 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); ShopUtils.addShop(shop, true);
executor.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.SHOP_CREATED)); executor.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.SHOP_CREATED));

View File

@ -1,6 +1,7 @@
package de.epiceric.shopchest.sql; package de.epiceric.shopchest.sql;
import de.epiceric.shopchest.ShopChest; import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
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.utils.ShopUtils; import de.epiceric.shopchest.utils.ShopUtils;
@ -19,6 +20,8 @@ public abstract class Database {
public ShopChest plugin; public ShopChest plugin;
public Connection connection; public Connection connection;
private int attempts = Config.database_reconnect_attempts;
public Database(ShopChest plugin) { public Database(ShopChest plugin) {
this.plugin = plugin; this.plugin = plugin;
initialize(); 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) * @return Lowest possible ID which is not used (> 0)
*/ */
public int getNextFreeID() { public int getNextFreeID(int reconnectAttempts) {
for (int i = 1; i < getHighestID() + 1; i++) { if (!isConnected()) {
if (get(i, ShopInfo.X) == null) { 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; return i;
} else { } else {
if (i == getHighestID()) { if (i == getHighestID(attempts)) {
return i + 1; return i + 1;
} }
} }
@ -84,7 +96,15 @@ public abstract class Database {
/** /**
* @return Highest ID which is used * @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; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
@ -116,7 +136,16 @@ public abstract class Database {
* *
* @param shop Shop to remove * @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; PreparedStatement ps = null;
try { try {
@ -135,7 +164,15 @@ public abstract class Database {
* @param shopInfo What to get * @param shopInfo What to get
* @return Value you wanted to get. This needs to be casted to the right type! * @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; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
@ -148,17 +185,17 @@ public abstract class Database {
switch (shopInfo) { switch (shopInfo) {
case SHOP: case SHOP:
Shop shop = ShopUtils.getShop((Location) get(id, ShopInfo.LOCATION)); Shop shop = ShopUtils.getShop((Location) get(id, ShopInfo.LOCATION, attempts));
if (shop != null) if (shop != null)
return shop; return shop;
else { else {
return new Shop(id, plugin, return new Shop(id, plugin,
(OfflinePlayer) get(id, ShopInfo.VENDOR), (OfflinePlayer) get(id, ShopInfo.VENDOR, attempts),
(ItemStack) get(id, ShopInfo.PRODUCT), (ItemStack) get(id, ShopInfo.PRODUCT, attempts),
(Location) get(id, ShopInfo.LOCATION), (Location) get(id, ShopInfo.LOCATION, attempts),
(double) get(id, ShopInfo.BUYPRICE), (double) get(id, ShopInfo.BUYPRICE, attempts),
(double) get(id, ShopInfo.SELLPRICE), (double) get(id, ShopInfo.SELLPRICE, attempts),
(ShopType) get(id, ShopInfo.SHOPTYPE)); (ShopType) get(id, ShopInfo.SHOPTYPE, attempts));
} }
case VENDOR: case VENDOR:
return Bukkit.getOfflinePlayer(UUID.fromString(rs.getString("vendor"))); return Bukkit.getOfflinePlayer(UUID.fromString(rs.getString("vendor")));
@ -173,7 +210,7 @@ public abstract class Database {
case Z: case Z:
return rs.getInt("z"); return rs.getInt("z");
case LOCATION: 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: case BUYPRICE:
return rs.getDouble("buyprice"); return rs.getDouble("buyprice");
case SELLPRICE: case SELLPRICE:
@ -184,14 +221,14 @@ public abstract class Database {
if (shoptype.equals("INFINITE")) { if (shoptype.equals("INFINITE")) {
Shop newShop = new Shop(id, plugin, Shop newShop = new Shop(id, plugin,
(OfflinePlayer) get(id, ShopInfo.VENDOR), (OfflinePlayer) get(id, ShopInfo.VENDOR, attempts),
(ItemStack) get(id, ShopInfo.PRODUCT), (ItemStack) get(id, ShopInfo.PRODUCT, attempts),
(Location) get(id, ShopInfo.LOCATION), (Location) get(id, ShopInfo.LOCATION, attempts),
(double) get(id, ShopInfo.BUYPRICE), (double) get(id, ShopInfo.BUYPRICE, attempts),
(double) get(id, ShopInfo.SELLPRICE), (double) get(id, ShopInfo.SELLPRICE, attempts),
ShopType.ADMIN); ShopType.ADMIN);
addShop(newShop); addShop(newShop, attempts);
return ShopType.ADMIN; return ShopType.ADMIN;
} }
@ -213,7 +250,16 @@ public abstract class Database {
* Adds a shop to the database * Adds a shop to the database
* @param shop Shop to add * @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; PreparedStatement ps = null;
try { 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} * Closes a {@link PreparedStatement} and a {@link ResultSet}
* @param ps {@link PreparedStatement} to close * @param ps {@link PreparedStatement} to close

View File

@ -81,7 +81,7 @@ public class ShopUtils {
} }
if (addToDatabase) if (addToDatabase)
plugin.getShopDatabase().addShop(shop); plugin.getShopDatabase().addShop(shop, Config.database_reconnect_attempts);
} }
@ -108,7 +108,7 @@ public class ShopUtils {
shop.removeHologram(); shop.removeHologram();
if (removeFromDatabase) if (removeFromDatabase)
plugin.getShopDatabase().removeShop(shop); plugin.getShopDatabase().removeShop(shop, Config.database_reconnect_attempts);
} }
/** /**
@ -212,10 +212,10 @@ public class ShopUtils {
} }
int count = 0; 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 { 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); ShopUtils.addShop(shop, false);
} catch (NullPointerException e) { } catch (NullPointerException e) {
continue; continue;