A lot of database work.

Database closing was occuring too early. In priort releases it was
hidden because the connection would be automatically made again. When
this was removed, it exposed this error.
Now the single database connection will not be closed until all
registered database objects have finished with their async queues.

Further, the database connecter was being made once for each database
type. This was a waste of resources and it also meant that static fields
were being used. Now, only one database connecter object is made and
there are no static fields.

https://github.com/BentoBoxWorld/BentoBox/issues/813
This commit is contained in:
tastybento 2019-07-05 20:11:06 -07:00
parent 014c5d574f
commit edd7bbf97a
25 changed files with 302 additions and 193 deletions

View File

@ -10,14 +10,16 @@ public interface DatabaseConnector {
/**
* Establishes a new connection to the database
*
* @param type of class
* @return A new connection to the database using the settings provided
*/
Object createConnection();
Object createConnection(Class<?> type);
/**
* Close the database connection
* @param type of class being closed
*/
void closeConnection();
void closeConnection(Class<?> type);
/**
* Returns the connection url
@ -44,5 +46,9 @@ public interface DatabaseConnector {
*/
boolean uniqueIdExists(String tableName, String key);
}

View File

@ -6,11 +6,13 @@ import world.bentobox.bentobox.database.DatabaseSetup;
public class JSONDatabase implements DatabaseSetup {
private JSONDatabaseConnector connector = new JSONDatabaseConnector(BentoBox.getInstance());
/* (non-Javadoc)
* @see world.bentobox.bentobox.database.DatabaseSetup#getHandler(java.lang.Class)
*/
@Override
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> dataObjectClass) {
return new JSONDatabaseHandler<>(BentoBox.getInstance(), dataObjectClass, new JSONDatabaseConnector(BentoBox.getInstance()));
return new JSONDatabaseHandler<>(BentoBox.getInstance(), dataObjectClass, connector);
}
}

View File

@ -38,18 +38,20 @@ public class JSONDatabaseConnector implements DatabaseConnector {
return file.exists();
}
@Override
public Object createConnection() {
return null; // Not used
}
@Override
public String getConnectionUrl() {
return null; // Not used
}
@Override
public void closeConnection() {
public Object createConnection(Class<?> type) {
// Not used
return null;
}
@Override
public void closeConnection(Class<?> type) {
// Not used
}
}

View File

@ -10,6 +10,7 @@ import world.bentobox.bentobox.database.DatabaseSetup;
* @since 1.1
*/
public class MariaDBDatabase implements DatabaseSetup {
private MariaDBDatabaseConnector connector;
/* (non-Javadoc)
* @see world.bentobox.bentobox.database.DatabaseSetup#getHandler(java.lang.Class)
@ -17,13 +18,16 @@ public class MariaDBDatabase implements DatabaseSetup {
@Override
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> type) {
BentoBox plugin = BentoBox.getInstance();
return new MariaDBDatabaseHandler<>(plugin, type, new MariaDBDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword()
)));
if (connector == null) {
connector = new MariaDBDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword()
));
}
return new MariaDBDatabaseHandler<>(plugin, type, connector);
}
}

View File

@ -3,6 +3,8 @@ package world.bentobox.bentobox.database.mariadb;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
@ -18,7 +20,8 @@ public class MariaDBDatabaseConnector implements DatabaseConnector {
private String connectionUrl;
private DatabaseConnectionSettingsImpl dbSettings;
private static Connection connection = null;
private Connection connection = null;
private Set<Class<?>> types = new HashSet<>();
/**
* Class for MariaDB database connections using the settings provided
@ -30,19 +33,6 @@ public class MariaDBDatabaseConnector implements DatabaseConnector {
+ "?autoReconnect=true&useSSL=false&allowMultiQueries=true";
}
@Override
public Connection createConnection() {
// Only get one connection at a time
if (connection == null) {
try {
connection = DriverManager.getConnection(connectionUrl, dbSettings.getUsername(), dbSettings.getPassword());
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
}
}
return connection;
}
@Override
public String getConnectionUrl() {
return connectionUrl;
@ -61,14 +51,31 @@ public class MariaDBDatabaseConnector implements DatabaseConnector {
return false;
}
@Override
public void closeConnection() {
if (connection != null) {
public void closeConnection(Class<?> type) {
types.remove(type);
if (types.isEmpty() && connection != null) {
try {
connection.close();
Bukkit.getLogger().info("Closed database connection");
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close MariaDB database connection");
}
}
}
@Override
public Object createConnection(Class<?> type) {
types.add(type);
// Only get one connection at a time
if (connection == null) {
try {
connection = DriverManager.getConnection(connectionUrl, dbSettings.getUsername(), dbSettings.getPassword());
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
}
}
return connection;
}
}

View File

@ -54,6 +54,8 @@ public class MariaDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
*/
private BukkitTask asyncSaveTask;
private boolean shutdown;
/**
* Handles the connection to the database and creation of the initial database schema (tables) for
@ -64,7 +66,7 @@ public class MariaDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
*/
MariaDBDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector dbConnecter) {
super(plugin, type, dbConnecter);
connection = (Connection)dbConnecter.createConnection();
connection = (Connection)dbConnecter.createConnection(dataObject);
if (connection == null) {
plugin.logError("Are the settings in config.yml correct?");
Bukkit.getPluginManager().disablePlugin(plugin);
@ -76,7 +78,10 @@ public class MariaDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
if (plugin.isEnabled()) {
asyncSaveTask = Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
// Loop continuously
while (plugin.isEnabled() || !processQueue.isEmpty()) {
while (!shutdown || !processQueue.isEmpty()) {
if (!plugin.isEnabled()) {
shutdown = true;
}
while (!processQueue.isEmpty()) {
processQueue.poll().run();
}
@ -90,6 +95,7 @@ public class MariaDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
}
// Cancel
asyncSaveTask.cancel();
dbConnecter.closeConnection(dataObject);
});
}
}
@ -272,6 +278,6 @@ public class MariaDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
@Override
public void close() {
databaseConnector.closeConnection();
shutdown = true;
}
}

View File

@ -9,6 +9,8 @@ import world.bentobox.bentobox.database.DatabaseSetup;
public class MongoDBDatabase implements DatabaseSetup {
private MongoDBDatabaseConnector connector;
/* (non-Javadoc)
* @see world.bentobox.bentobox.database.DatabaseSetup#getHandler(java.lang.Class)
*/
@ -22,13 +24,16 @@ public class MongoDBDatabase implements DatabaseSetup {
Bukkit.getServer().getPluginManager().disablePlugin(plugin);
return null;
}
return new MongoDBDatabaseHandler<>(plugin, type, new MongoDBDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword()
)));
if (connector == null) {
connector = new MongoDBDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword()
));
}
return new MongoDBDatabaseHandler<>(plugin, type, connector);
}
}

View File

@ -1,5 +1,9 @@
package world.bentobox.bentobox.database.mongodb;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
import com.mongodb.MongoClient;
@ -13,8 +17,9 @@ import world.bentobox.bentobox.database.DatabaseConnector;
public class MongoDBDatabaseConnector implements DatabaseConnector {
private static MongoClient client;
private MongoClient client;
private DatabaseConnectionSettingsImpl dbSettings;
private Set<Class<?>> types = new HashSet<>();
/**
* Class for MySQL database connections using the settings provided
@ -25,7 +30,8 @@ public class MongoDBDatabaseConnector implements DatabaseConnector {
}
@Override
public MongoDatabase createConnection() {
public MongoDatabase createConnection(Class<?> type) {
types.add(type);
// Only get one client
if (client == null) {
MongoCredential credential = MongoCredential.createCredential(dbSettings.getUsername(),
@ -56,8 +62,12 @@ public class MongoDBDatabaseConnector implements DatabaseConnector {
}
@Override
public void closeConnection() {
client.close();
public void closeConnection(Class<?> type) {
types.remove(type);
if (types.isEmpty() && client != null) {
client.close();
Bukkit.getLogger().info("Closed database connection");
}
}
}

View File

@ -49,7 +49,7 @@ public class MongoDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
this.dbConnecter = dbConnecter;
// Connection to the database
MongoDatabase database = (MongoDatabase) dbConnecter.createConnection();
MongoDatabase database = (MongoDatabase) dbConnecter.createConnection(dataObject);
if (database == null) {
plugin.logError("Are the settings in config.yml correct?");
Bukkit.getPluginManager().disablePlugin(plugin);
@ -146,6 +146,6 @@ public class MongoDBDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
@Override
public void close() {
dbConnecter.closeConnection();
dbConnecter.closeConnection(dataObject);
}
}

View File

@ -7,19 +7,24 @@ import world.bentobox.bentobox.database.DatabaseSetup;
public class MySQLDatabase implements DatabaseSetup {
private MySQLDatabaseConnector connector;
/* (non-Javadoc)
* @see world.bentobox.bentobox.database.DatabaseSetup#getHandler(java.lang.Class)
*/
@Override
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> type) {
BentoBox plugin = BentoBox.getInstance();
return new MySQLDatabaseHandler<>(plugin, type, new MySQLDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword()
)));
if (connector == null) {
connector = new MySQLDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword()
));
}
return new MySQLDatabaseHandler<>(plugin, type, connector);
}
}

View File

@ -3,6 +3,8 @@ package world.bentobox.bentobox.database.mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
@ -14,7 +16,8 @@ public class MySQLDatabaseConnector implements DatabaseConnector {
private String connectionUrl;
private DatabaseConnectionSettingsImpl dbSettings;
private static Connection connection = null;
private Connection connection = null;
private Set<Class<?>> types = new HashSet<>();
/**
* Class for MySQL database connections using the settings provided
@ -26,19 +29,6 @@ public class MySQLDatabaseConnector implements DatabaseConnector {
+ "?autoReconnect=true&useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8";
}
@Override
public Connection createConnection() {
// Only make one connection to the database
if (connection == null) {
try {
connection = DriverManager.getConnection(connectionUrl, dbSettings.getUsername(), dbSettings.getPassword());
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
}
}
return connection;
}
@Override
public String getConnectionUrl() {
return connectionUrl;
@ -58,13 +48,29 @@ public class MySQLDatabaseConnector implements DatabaseConnector {
}
@Override
public void closeConnection() {
if (connection != null) {
public void closeConnection(Class<?> type) {
types.remove(type);
if (types.isEmpty() && connection != null) {
try {
connection.close();
Bukkit.getLogger().info("Closed database connection");
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close MySQL database connection");
}
}
}
@Override
public Object createConnection(Class<?> type) {
types.add(type);
// Only make one connection to the database
if (connection == null) {
try {
connection = DriverManager.getConnection(connectionUrl, dbSettings.getUsername(), dbSettings.getPassword());
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
}
}
return connection;
}
}

View File

@ -55,6 +55,8 @@ public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
*/
private BukkitTask asyncSaveTask;
private boolean shutdown;
/**
* Handles the connection to the database and creation of the initial database schema (tables) for
@ -65,7 +67,7 @@ public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
*/
MySQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector dbConnecter) {
super(plugin, type, dbConnecter);
connection = (Connection)dbConnecter.createConnection();
connection = (Connection)dbConnecter.createConnection(dataObject);
if (connection == null) {
plugin.logError("Are the settings in config.yml correct?");
Bukkit.getPluginManager().disablePlugin(plugin);
@ -77,7 +79,11 @@ public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
if (plugin.isEnabled()) {
asyncSaveTask = Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
// Loop continuously
while (plugin.isEnabled() || !processQueue.isEmpty()) {
while (!shutdown || !processQueue.isEmpty()) {
// This catches any databases that are not explicitly closed
if (!plugin.isEnabled()) {
shutdown = true;
}
while (!processQueue.isEmpty()) {
processQueue.poll().run();
}
@ -91,6 +97,7 @@ public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
}
// Cancel
asyncSaveTask.cancel();
dbConnecter.closeConnection(dataObject);
});
}
}
@ -274,6 +281,6 @@ public class MySQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
@Override
public void close() {
databaseConnector.closeConnection();
shutdown = true;
}
}

View File

@ -11,15 +11,20 @@ import world.bentobox.bentobox.database.DatabaseSetup;
*/
public class PostgreSQLDatabase implements DatabaseSetup {
PostgreSQLDatabaseConnector connector;
@Override
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> dataObjectClass) {
BentoBox plugin = BentoBox.getInstance();
return new PostgreSQLDatabaseHandler<>(plugin, dataObjectClass, new PostgreSQLDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword()
)));
if (connector == null) {
connector = new PostgreSQLDatabaseConnector(new DatabaseConnectionSettingsImpl(
plugin.getSettings().getDatabaseHost(),
plugin.getSettings().getDatabasePort(),
plugin.getSettings().getDatabaseName(),
plugin.getSettings().getDatabaseUsername(),
plugin.getSettings().getDatabasePassword()
));
}
return new PostgreSQLDatabaseHandler<>(plugin, dataObjectClass, connector);
}
}

View File

@ -3,6 +3,8 @@ package world.bentobox.bentobox.database.postgresql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
@ -18,7 +20,8 @@ public class PostgreSQLDatabaseConnector implements DatabaseConnector {
private String connectionUrl;
private DatabaseConnectionSettingsImpl dbSettings;
private static Connection connection = null;
private Connection connection = null;
private Set<Class<?>> types = new HashSet<>();
/**
* Class for PostgreSQL database connections using the settings provided
@ -27,31 +30,7 @@ public class PostgreSQLDatabaseConnector implements DatabaseConnector {
PostgreSQLDatabaseConnector(@NonNull DatabaseConnectionSettingsImpl dbSettings) {
this.dbSettings = dbSettings;
connectionUrl = "jdbc:postgresql://" + dbSettings.getHost() + ":" + dbSettings.getPort() + "/" + dbSettings.getDatabaseName()
+ "?autoReconnect=true&useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8";
}
@Override
public Object createConnection() {
// Only make one connection to the database
if (connection == null) {
try {
connection = DriverManager.getConnection(connectionUrl, dbSettings.getUsername(), dbSettings.getPassword());
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
}
}
return connection;
}
@Override
public void closeConnection() {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close PostgreSQL database connection");
}
}
+ "?autoReconnect=true&useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8";
}
@Override
@ -70,4 +49,31 @@ public class PostgreSQLDatabaseConnector implements DatabaseConnector {
// Not used
return false;
}
@Override
public void closeConnection(Class<?> type) {
types.remove(type);
if (types.isEmpty() && connection != null) {
try {
connection.close();
Bukkit.getLogger().info("Closed database connection");
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close PostgreSQL database connection");
}
}
}
@Override
public Object createConnection(Class<?> type) {
types.add(type);
// Only make one connection to the database
if (connection == null) {
try {
connection = DriverManager.getConnection(connectionUrl, dbSettings.getUsername(), dbSettings.getPassword());
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
}
}
return connection;
}
}

View File

@ -57,6 +57,8 @@ public class PostgreSQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T>
*/
private BukkitTask asyncSaveTask;
private boolean shutdown;
/**
* Constructor
*
@ -67,7 +69,7 @@ public class PostgreSQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T>
*/
protected PostgreSQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector) {
super(plugin, type, databaseConnector);
connection = (Connection) databaseConnector.createConnection();
connection = (Connection) databaseConnector.createConnection(dataObject);
if (connection == null) {
plugin.logError("Are the settings in config.yml correct?");
Bukkit.getPluginManager().disablePlugin(plugin);
@ -79,7 +81,8 @@ public class PostgreSQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T>
if (plugin.isEnabled()) {
asyncSaveTask = Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
// Loop continuously
while (plugin.isEnabled() || !processQueue.isEmpty()) {
while (!shutdown || !processQueue.isEmpty()) {
while (!processQueue.isEmpty()) {
processQueue.poll().run();
}
@ -93,6 +96,7 @@ public class PostgreSQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T>
}
// Cancel
asyncSaveTask.cancel();
databaseConnector.closeConnection(dataObject);
});
}
}
@ -171,7 +175,7 @@ public class PostgreSQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T>
@Override
public void saveObject(T instance) throws IllegalAccessException, InvocationTargetException, IntrospectionException {
// Null check
// Null check
if (instance == null) {
plugin.logError("MySQL database request to store a null. ");
return;
@ -261,7 +265,7 @@ public class PostgreSQLDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T>
@Override
public void close() {
shutdown = true;
}
@Override

View File

@ -10,8 +10,10 @@ import world.bentobox.bentobox.database.DatabaseSetup;
*/
public class SQLiteDatabase implements DatabaseSetup {
private SQLiteDatabaseConnector connector = new SQLiteDatabaseConnector(BentoBox.getInstance());
@Override
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> dataObjectClass) {
return new SQLiteDatabaseHandler<>(BentoBox.getInstance(), dataObjectClass, new SQLiteDatabaseConnector(BentoBox.getInstance()));
return new SQLiteDatabaseHandler<>(BentoBox.getInstance(), dataObjectClass, connector);
}
}

View File

@ -4,6 +4,8 @@ import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.eclipse.jdt.annotation.NonNull;
@ -18,38 +20,20 @@ import world.bentobox.bentobox.database.DatabaseConnector;
public class SQLiteDatabaseConnector implements DatabaseConnector {
private String connectionUrl;
private static Connection connection = null;
private Connection connection = null;
private static final String DATABASE_FOLDER_NAME = "database";
private Set<Class<?>> types = new HashSet<>();
SQLiteDatabaseConnector(@NonNull BentoBox plugin) {
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
if (!dataFolder.exists()) {
if (!dataFolder.mkdirs()) {
BentoBox.getInstance().logError("Could not create database folder!");
}
}
connectionUrl = "jdbc:sqlite:" + dataFolder.getAbsolutePath() + File.separator + "database.db";
}
@Override
public Object createConnection() {
// Only make one connection at a time
if (connection == null) {
try {
connection = DriverManager.getConnection(connectionUrl);
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
}
}
return connection;
}
@Override
public void closeConnection() {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close SQLite database connection");
}
}
}
@Override
public String getConnectionUrl() {
return connectionUrl;
@ -67,4 +51,31 @@ public class SQLiteDatabaseConnector implements DatabaseConnector {
// Not used
return false;
}
@Override
public void closeConnection(Class<?> type) {
types.remove(type);
if (types.isEmpty() && connection != null) {
try {
connection.close();
Bukkit.getLogger().info("Closed database connection");
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close SQLite database connection");
}
}
}
@Override
public Object createConnection(Class<?> type) {
types.add(type);
// Only make one connection at a time
if (connection == null) {
try {
connection = DriverManager.getConnection(connectionUrl);
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not connect to the database! " + e.getMessage());
}
}
return connection;
}
}

View File

@ -45,7 +45,7 @@ public class SQLiteDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
*/
protected SQLiteDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector) {
super(plugin, type, databaseConnector);
connection = (Connection) databaseConnector.createConnection();
connection = (Connection) databaseConnector.createConnection(dataObject);
if (connection == null) {
plugin.logError("Are the settings in config.yml correct?");
Bukkit.getPluginManager().disablePlugin(plugin);
@ -198,7 +198,7 @@ public class SQLiteDatabaseHandler<T> extends AbstractJSONDatabaseHandler<T> {
@Override
public void close() {
databaseConnector.closeConnection();
databaseConnector.closeConnection(dataObject);
}
@Override

View File

@ -6,6 +6,8 @@ import world.bentobox.bentobox.database.DatabaseSetup;
public class YamlDatabase implements DatabaseSetup {
private YamlDatabaseConnector connector = new YamlDatabaseConnector(BentoBox.getInstance());
/**
* Get the config
* @param <T> - Class type
@ -13,7 +15,7 @@ public class YamlDatabase implements DatabaseSetup {
* @return - the config handler
*/
public <T> AbstractDatabaseHandler<T> getConfig(Class<T> type) {
return new ConfigHandler<>(BentoBox.getInstance(), type, new YamlDatabaseConnector(BentoBox.getInstance()));
return new ConfigHandler<>(BentoBox.getInstance(), type, connector);
}
/* (non-Javadoc)
@ -21,7 +23,7 @@ public class YamlDatabase implements DatabaseSetup {
*/
@Override
public <T> AbstractDatabaseHandler<T> getHandler(Class<T> type) {
return new YamlDatabaseHandler<>(BentoBox.getInstance(), type, new YamlDatabaseConnector(BentoBox.getInstance()));
return new YamlDatabaseHandler<>(BentoBox.getInstance(), type, connector);
}
}

View File

@ -13,7 +13,6 @@ import java.io.PrintWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -44,11 +43,6 @@ public class YamlDatabaseConnector implements DatabaseConnector {
dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
}
@Override
public Connection createConnection() {
return null; // Not used
}
@Override
public String getConnectionUrl() {
return null; // Not used
@ -211,8 +205,16 @@ public class YamlDatabaseConnector implements DatabaseConnector {
}
@Override
public void closeConnection() {
public Object createConnection(Class<?> type) {
// Not used
return null;
}
@Override
public void closeConnection(Class<?> type) {
// not used
}
}

View File

@ -110,6 +110,14 @@ public class IslandsManager {
deletedIslands = new ArrayList<>();
}
/**
* Used only for testing. Sets the database to a mock database.
* @param handler - handler
*/
public void setHandler(Database<Island> handler) {
this.handler = handler;
}
/**
* This is a generic scan that can work in the overworld or the nether
* @param l - location around which to scan
@ -930,7 +938,6 @@ public class IslandsManager {
plugin.logError("Could not save island to database when running sync! " + e.getMessage());
}
}
}
/**

View File

@ -96,7 +96,7 @@ public class MariaDBDatabaseHandlerTest {
when(Bukkit.getPluginManager()).thenReturn(pluginManager);
// MySQLDatabaseConnector
when(dbConn.createConnection()).thenReturn(connection);
when(dbConn.createConnection(any())).thenReturn(connection);
// Queries
when(connection.prepareStatement(Mockito.anyString())).thenReturn(ps);
@ -393,17 +393,6 @@ public class MariaDBDatabaseHandlerTest {
verify(plugin).logError(eq("Could not check if key exists in database! hello error"));
}
/**
* Test method for {@link world.bentobox.bentobox.database.mariadb.MariaDBDatabaseHandler#close()}.
* @throws SQLException
*/
@Ignore("it doesn't recognize the #close() ran in the database connector")
@Test
public void testClose() throws SQLException {
handler.close();
verify(dbConn).closeConnection();
}
/**
* Test method for {@link world.bentobox.bentobox.database.mariadb.MariaDBDatabaseHandler#deleteID(java.lang.String)}.
* @throws SQLException
@ -435,7 +424,7 @@ public class MariaDBDatabaseHandlerTest {
*/
@Test
public void testMariaDBDatabaseHandlerBadPassword() {
when(dbConn.createConnection()).thenReturn(null);
when(dbConn.createConnection(any())).thenReturn(null);
new MariaDBDatabaseHandler<>(plugin, Island.class, dbConn);
verify(plugin).logError("Are the settings in config.yml correct?");
verify(pluginManager).disablePlugin(plugin);
@ -447,8 +436,7 @@ public class MariaDBDatabaseHandlerTest {
*/
@Test
public void testMariaDBDatabaseHandlerCreateSchema() throws SQLException {
verify(dbConn).createConnection();
//verify(connection).prepareStatement("CREATE TABLE IF NOT EXISTS `world.bentobox.bentobox.database.objects.Island` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), UNIQUE INDEX i (uniqueId) )");
verify(dbConn).createConnection(any());
verify(connection).prepareStatement("CREATE TABLE IF NOT EXISTS `world.bentobox.bentobox.database.objects.Island` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (JSON_EXTRACT(json, \"$.uniqueId\")), UNIQUE INDEX i (uniqueId))");
}

View File

@ -1,6 +1,3 @@
/**
*
*/
package world.bentobox.bentobox.database.mysql;
import static org.junit.Assert.assertEquals;
@ -92,7 +89,7 @@ public class MySQLDatabaseConnectorTest {
@Test
public void testCreateConnection() {
MySQLDatabaseConnector dc = new MySQLDatabaseConnector(dbSettings);
assertEquals(connection, dc.createConnection());
assertEquals(connection, dc.createConnection(null));
}
/**
@ -104,7 +101,7 @@ public class MySQLDatabaseConnectorTest {
PowerMockito.doThrow(new SQLException("error")).when(DriverManager.class);
DriverManager.getConnection(any(), any(), any());
MySQLDatabaseConnector dc = new MySQLDatabaseConnector(dbSettings);
dc.createConnection();
dc.createConnection(null);
verify(logger).severe("Could not connect to the database! No suitable driver found for jdbc:mysql://localhost:1234/bentobox?autoReconnect=true&useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8");
}
@ -141,8 +138,8 @@ public class MySQLDatabaseConnectorTest {
@Test
public void testCloseConnection() {
MySQLDatabaseConnector dc = new MySQLDatabaseConnector(dbSettings);
dc.createConnection();
dc.closeConnection();
dc.createConnection(null);
dc.closeConnection(null);
}
/**
@ -151,8 +148,8 @@ public class MySQLDatabaseConnectorTest {
@Test
public void testCloseConnectionError() throws SQLException {
MySQLDatabaseConnector dc = new MySQLDatabaseConnector(dbSettings);
dc.createConnection();
dc.closeConnection();
dc.createConnection(null);
dc.closeConnection(null);
}
}

View File

@ -95,7 +95,7 @@ public class MySQLDatabaseHandlerTest {
when(Bukkit.getPluginManager()).thenReturn(pluginManager);
// MySQLDatabaseConnector
when(dbConn.createConnection()).thenReturn(connection);
when(dbConn.createConnection(any())).thenReturn(connection);
// Queries
when(connection.prepareStatement(Mockito.anyString())).thenReturn(ps);
@ -389,17 +389,6 @@ public class MySQLDatabaseHandlerTest {
verify(plugin).logError(eq("Could not check if key exists in database! hello error"));
}
/**
* Test method for {@link world.bentobox.bentobox.database.mysql.MySQLDatabaseHandler#close()}.
* @throws SQLException
*/
@Ignore("it doesn't recognize the #close() ran in the database connector")
@Test
public void testClose() throws SQLException {
handler.close();
verify(dbConn).closeConnection();
}
/**
* Test method for {@link world.bentobox.bentobox.database.mysql.MySQLDatabaseHandler#deleteID(java.lang.String)}.
* @throws SQLException
@ -431,7 +420,7 @@ public class MySQLDatabaseHandlerTest {
*/
@Test
public void testMySQLDatabaseHandlerBadPassword() {
when(dbConn.createConnection()).thenReturn(null);
when(dbConn.createConnection(any())).thenReturn(null);
new MySQLDatabaseHandler<>(plugin, Island.class, dbConn);
verify(plugin).logError("Are the settings in config.yml correct?");
verify(pluginManager).disablePlugin(plugin);
@ -443,7 +432,7 @@ public class MySQLDatabaseHandlerTest {
*/
@Test
public void testMySQLDatabaseHandlerCreateSchema() throws SQLException {
verify(dbConn).createConnection();
verify(dbConn).createConnection(any());
verify(connection).prepareStatement("CREATE TABLE IF NOT EXISTS `world.bentobox.bentobox.database.objects.Island` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), UNIQUE INDEX i (uniqueId) )");
}

View File

@ -9,9 +9,14 @@ import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -42,6 +47,7 @@ import org.bukkit.entity.Wither;
import org.bukkit.entity.Zombie;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitScheduler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -61,6 +67,7 @@ import world.bentobox.bentobox.Settings;
import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.api.events.island.IslandEvent.IslandDeleteEvent;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.lists.Flags;
@ -100,12 +107,33 @@ public class IslandsManagerTest {
private Island is;
@Mock
private PluginManager pim;
// Database
Database<Island> db;
/**
* @throws java.lang.Exception
*/
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
// Clear any lingering database
clear();
// Set up plugin
plugin = mock(BentoBox.class);
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// island world mgr
when(world.getName()).thenReturn("world");
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
when(iwm.inWorld(any(World.class))).thenReturn(true);
when(iwm.inWorld(any(Location.class))).thenReturn(true);
when(plugin.getIWM()).thenReturn(iwm);
// Settings
Settings s = mock(Settings.class);
when(plugin.getSettings()).thenReturn(s);
when(s.getDatabaseType()).thenReturn(DatabaseType.JSON);
// World
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
// Set up plugin
@ -114,12 +142,6 @@ public class IslandsManagerTest {
// Command manager
CommandsManager cm = mock(CommandsManager.class);
when(plugin.getCommandsManager()).thenReturn(cm);
// Settings
Settings s = mock(Settings.class);
when(plugin.getSettings()).thenReturn(s);
when(s.getDatabaseType()).thenReturn(DatabaseType.JSON);
// Player
when(user.isOp()).thenReturn(false);
uuid = UUID.randomUUID();
@ -198,8 +220,22 @@ public class IslandsManagerTest {
// Cover hostile entities
when(Util.isHostileEntity(Mockito.any())).thenCallRealMethod();
// database must be mocked here
db = mock(Database.class);
}
@After
public void clear() throws IOException{
//remove any database data
File file = new File("database");
Path pathToBeDeleted = file.toPath();
if (file.exists()) {
Files.walk(pathToBeDeleted)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
}
/**
* Test method for {@link world.bentobox.bentobox.managers.IslandsManager#isSafeLocation(org.bukkit.Location)}.