mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-10-04 01:27:42 +02:00
WIP using JSON and GSON for database.
Causes stack overflow right now. In the middle of debugging, but I need this in github so I can grab it elsewhere.
This commit is contained in:
parent
e598fa7c93
commit
fcede01a11
@ -4,6 +4,7 @@ import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase;
|
||||
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
|
||||
import us.tastybento.bskyblock.database.mysql.MySQLDatabase;
|
||||
import us.tastybento.bskyblock.database.mysqljson.MySQLDatabaseJ;
|
||||
|
||||
public abstract class BSBDatabase {
|
||||
|
||||
@ -23,7 +24,9 @@ public abstract class BSBDatabase {
|
||||
|
||||
public enum DatabaseType{
|
||||
FLATFILE(new FlatFileDatabase()),
|
||||
MYSQL(new MySQLDatabase());
|
||||
MYSQL(new MySQLDatabase()),
|
||||
//JSON();
|
||||
MYSQLJ(new MySQLDatabaseJ());
|
||||
|
||||
BSBDatabase database;
|
||||
|
||||
|
@ -56,19 +56,6 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
super(plugin, type, databaseConnecter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String createSelectQuery() {
|
||||
return ""; // not used
|
||||
}
|
||||
@Override
|
||||
protected String createInsertQuery() {
|
||||
return ""; // not used
|
||||
}
|
||||
@Override
|
||||
protected String createDeleteQuery() {
|
||||
return ""; // Not used
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#loadObject(java.lang.String)
|
||||
*/
|
||||
|
@ -30,12 +30,6 @@ public abstract class AbstractDatabaseHandler<T> {
|
||||
*/
|
||||
protected DatabaseConnecter databaseConnecter;
|
||||
|
||||
/** The SQL-select- and insert query */
|
||||
protected final String selectQuery;
|
||||
protected final String insertQuery;
|
||||
protected final String deleteQuery;
|
||||
|
||||
|
||||
protected Plugin plugin;
|
||||
|
||||
|
||||
@ -53,20 +47,8 @@ public abstract class AbstractDatabaseHandler<T> {
|
||||
this.plugin = plugin;
|
||||
this.databaseConnecter = databaseConnecter;
|
||||
this.dataObject = type;
|
||||
this.selectQuery = createSelectQuery();
|
||||
this.insertQuery = createInsertQuery();
|
||||
this.deleteQuery = createDeleteQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the SQL-String to insert into / select / delete from the database
|
||||
* Not used in the flat file database
|
||||
* @return the SQL-String
|
||||
*/
|
||||
protected abstract String createSelectQuery();
|
||||
protected abstract String createInsertQuery();
|
||||
protected abstract String createDeleteQuery();
|
||||
|
||||
/**
|
||||
* Loads all the records in this table and returns a list of them
|
||||
* @return list of <T>
|
||||
|
@ -25,7 +25,7 @@ import us.tastybento.bskyblock.database.objects.Players;
|
||||
|
||||
public class PlayersManager{
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG = true;
|
||||
private BSkyBlock plugin;
|
||||
private BSBDatabase database;
|
||||
private AbstractDatabaseHandler<Players> handler;
|
||||
@ -250,7 +250,7 @@ public class PlayersManager{
|
||||
public void setHomeLocation(UUID playerUUID, Location location, int number) {
|
||||
addPlayer(playerUUID);
|
||||
playerCache.get(playerUUID).setHomeLocation(location,number);
|
||||
this.save(true);
|
||||
//this.save(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,7 +261,7 @@ public class PlayersManager{
|
||||
public void setHomeLocation(UUID playerUUID, Location location) {
|
||||
addPlayer(playerUUID);
|
||||
playerCache.get(playerUUID).setHomeLocation(location,1);
|
||||
this.save(true);
|
||||
//this.save(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,8 +113,8 @@ public class NewIsland {
|
||||
// Add to the grid
|
||||
island = plugin.getIslands().createIsland(next, playerUUID);
|
||||
// Save the player so that if the server is reset weird things won't happen
|
||||
plugin.getPlayers().save(true);
|
||||
plugin.getIslands().save(true);
|
||||
//plugin.getPlayers().save(true);
|
||||
//plugin.getIslands().save(true);
|
||||
|
||||
// Clear any old home locations (they should be clear, but just in case)
|
||||
plugin.getPlayers().clearHomeLocations(playerUUID);
|
||||
|
@ -151,8 +151,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
setSql.append(dataObject.getCanonicalName());
|
||||
setSql.append(".");
|
||||
setSql.append(field.getName());
|
||||
setSql.append("` (");
|
||||
setSql.append("uniqueId VARCHAR(36) NOT NULL, ");
|
||||
setSql.append("` (uniqueId VARCHAR(36) NOT NULL, ");
|
||||
// Get columns separated by commas
|
||||
setSql.append(getCollectionColumnString(writeMethod,false,true));
|
||||
// Close the SQL string
|
||||
@ -306,11 +305,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
return columns;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#createSelectQuery()
|
||||
*/
|
||||
@Override
|
||||
protected String createSelectQuery() {
|
||||
String createSelectQuery() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@ -324,12 +319,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#createInsertQuery()
|
||||
*/
|
||||
@Override
|
||||
protected String createInsertQuery() {
|
||||
String createInsertQuery() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// Replace into is used so that any data in the table will be replaced with updated data
|
||||
@ -348,8 +338,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String createDeleteQuery() {
|
||||
String createDeleteQuery() {
|
||||
return "DELETE FROM [table_name] WHERE uniqueId = ?";
|
||||
}
|
||||
|
||||
@ -357,14 +346,6 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
* Inserts a <T> into the corresponding database-table
|
||||
*
|
||||
* @param instance <T> that should be inserted into the corresponding database-table. Must extend DataObject.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#insertObject(java.lang.Object)
|
||||
@ -375,8 +356,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
InstantiationException, IllegalAccessException,
|
||||
IntrospectionException, InvocationTargetException, NoSuchMethodException {
|
||||
|
||||
// insertQuery is created in super from the createInsertQuery() method
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(insertQuery)) {
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(createInsertQuery())) {
|
||||
// Get the uniqueId. As each class extends DataObject, it must have this method in it.
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", dataObject);
|
||||
Method getUniqueId = propertyDescriptor.getReadMethod();
|
||||
@ -538,14 +518,6 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
* @return List of <T>s filled with values from the corresponding
|
||||
* database-table
|
||||
*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
@Override
|
||||
public List<T> loadObjects() throws SQLException,
|
||||
@ -554,7 +526,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
IntrospectionException, InvocationTargetException, ClassNotFoundException {
|
||||
|
||||
try (Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(selectQuery)) {
|
||||
ResultSet resultSet = statement.executeQuery(createSelectQuery())) {
|
||||
return createObjects(resultSet);
|
||||
}
|
||||
}
|
||||
@ -600,14 +572,6 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
*
|
||||
* @return List of <T>s filled with values from the provided ResultSet
|
||||
*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<T> createObjects(ResultSet resultSet)
|
||||
@ -774,47 +738,46 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
InvocationTargetException, IntrospectionException, SQLException, NoSuchMethodException, SecurityException {
|
||||
// Delete this object from all tables
|
||||
// Try to connect to the database
|
||||
try (Connection conn = databaseConnecter.createConnection()){
|
||||
// Get the uniqueId. As each class extends DataObject, it must have this method in it.
|
||||
Method getUniqueId = dataObject.getMethod("getUniqueId");
|
||||
String uniqueId = (String) getUniqueId.invoke(instance);
|
||||
//plugin.getLogger().info("DEBUG: Unique Id = " + uniqueId);
|
||||
if (uniqueId.isEmpty()) {
|
||||
throw new SQLException("uniqueId is blank");
|
||||
}
|
||||
// Delete from the main table
|
||||
// First substitution is the table name
|
||||
// deleteQuery is created in super from the createInsertQuery() method
|
||||
try (PreparedStatement preparedStatement = conn.prepareStatement(deleteQuery.replace("[table_name]", "`" + dataObject.getCanonicalName() + "`"))) {
|
||||
// Second is the unique ID
|
||||
preparedStatement.setString(1, uniqueId);
|
||||
preparedStatement.addBatch();
|
||||
preparedStatement.executeBatch();
|
||||
}
|
||||
// Get the uniqueId. As each class extends DataObject, it must have this method in it.
|
||||
Method getUniqueId = dataObject.getMethod("getUniqueId");
|
||||
String uniqueId = (String) getUniqueId.invoke(instance);
|
||||
//plugin.getLogger().info("DEBUG: Unique Id = " + uniqueId);
|
||||
if (uniqueId.isEmpty()) {
|
||||
throw new SQLException("uniqueId is blank");
|
||||
}
|
||||
// Delete from the main table
|
||||
// First substitution is the table name
|
||||
// deleteQuery is created in super from the createInsertQuery() method
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(createDeleteQuery().replace("[table_name]", "`" + dataObject.getCanonicalName() + "`"))) {
|
||||
// Second is the unique ID
|
||||
preparedStatement.setString(1, uniqueId);
|
||||
preparedStatement.addBatch();
|
||||
preparedStatement.executeBatch();
|
||||
}
|
||||
|
||||
// Delete from any sub tables created from the object
|
||||
// Run through the fields in the class using introspection
|
||||
for (Field field : dataObject.getDeclaredFields()) {
|
||||
// Get the field's property descriptor
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
|
||||
// Delete Collection tables
|
||||
if (propertyDescriptor.getPropertyType().equals(Set.class) ||
|
||||
propertyDescriptor.getPropertyType().equals(Map.class) ||
|
||||
propertyDescriptor.getPropertyType().equals(HashMap.class) ||
|
||||
propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
|
||||
// First substitution is the table name
|
||||
try (PreparedStatement preparedStatement2 = conn.prepareStatement(deleteQuery.replace("[table_name]", "`" + dataObject.getCanonicalName() + "." + field.getName() + "`"))) {
|
||||
// Second is the unique ID
|
||||
preparedStatement2.setString(1, uniqueId);
|
||||
preparedStatement2.addBatch();
|
||||
// Execute
|
||||
preparedStatement2.executeBatch();
|
||||
}
|
||||
// Delete from any sub tables created from the object
|
||||
// Run through the fields in the class using introspection
|
||||
for (Field field : dataObject.getDeclaredFields()) {
|
||||
// Get the field's property descriptor
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
|
||||
// Delete Collection tables
|
||||
if (propertyDescriptor.getPropertyType().equals(Set.class) ||
|
||||
propertyDescriptor.getPropertyType().equals(Map.class) ||
|
||||
propertyDescriptor.getPropertyType().equals(HashMap.class) ||
|
||||
propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
|
||||
// First substitution is the table name
|
||||
try (PreparedStatement preparedStatement2 = connection.prepareStatement(createDeleteQuery().replace("[table_name]", "`" + dataObject.getCanonicalName() + "." + field.getName() + "`"))) {
|
||||
// Second is the unique ID
|
||||
preparedStatement2.setString(1, uniqueId);
|
||||
preparedStatement2.addBatch();
|
||||
// Execute
|
||||
preparedStatement2.executeBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#objectExists(java.lang.String)
|
||||
*/
|
||||
@ -826,8 +789,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
query.append(dataObject.getCanonicalName());
|
||||
query.append("` WHERE `uniqueId` = ?), 1, 0)");
|
||||
|
||||
try (Connection conn = databaseConnecter.createConnection();
|
||||
PreparedStatement preparedStatement = conn.prepareStatement(query.toString())) {
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(query.toString())) {
|
||||
preparedStatement.setString(1, key);
|
||||
try (ResultSet resultSet = preparedStatement.executeQuery()) {
|
||||
if (resultSet.next()) {
|
||||
|
@ -0,0 +1,88 @@
|
||||
package us.tastybento.bskyblock.database.mysqljson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
public class LocationAdapter implements JsonDeserializer<Location>, JsonSerializer<Location> {
|
||||
|
||||
public static final LocationAdapter INSTANCE = new LocationAdapter();
|
||||
|
||||
@Override
|
||||
public Location deserialize( JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext ) throws JsonParseException {
|
||||
|
||||
if ( !json.isJsonObject() ) {
|
||||
throw new JsonParseException( "not a JSON object" );
|
||||
}
|
||||
|
||||
final JsonObject obj = (JsonObject) json;
|
||||
final JsonElement world = obj.get( "world" );
|
||||
final JsonElement x = obj.get( "x" );
|
||||
final JsonElement y = obj.get( "y" );
|
||||
final JsonElement z = obj.get( "z" );
|
||||
final JsonElement yaw = obj.get( "yaw" );
|
||||
final JsonElement pitch = obj.get( "pitch" );
|
||||
|
||||
if ( world == null || x == null || y == null || z == null || yaw == null || pitch == null ) {
|
||||
throw new JsonParseException( "Malformed location json string!" );
|
||||
}
|
||||
|
||||
if ( !world.isJsonPrimitive() || !((JsonPrimitive) world).isString() ) {
|
||||
throw new JsonParseException( "world is not a string" );
|
||||
}
|
||||
|
||||
if ( !x.isJsonPrimitive() || !((JsonPrimitive) x).isNumber() ) {
|
||||
throw new JsonParseException( "x is not a number" );
|
||||
}
|
||||
|
||||
if ( !y.isJsonPrimitive() || !((JsonPrimitive) y).isNumber() ) {
|
||||
throw new JsonParseException( "y is not a number" );
|
||||
}
|
||||
|
||||
if ( !z.isJsonPrimitive() || !((JsonPrimitive) z).isNumber() ) {
|
||||
throw new JsonParseException( "z is not a number" );
|
||||
}
|
||||
|
||||
if ( !yaw.isJsonPrimitive() || !((JsonPrimitive) yaw).isNumber() ) {
|
||||
throw new JsonParseException( "yaw is not a number" );
|
||||
}
|
||||
|
||||
if ( !pitch.isJsonPrimitive() || !((JsonPrimitive) pitch).isNumber() ) {
|
||||
throw new JsonParseException( "pitch is not a number" );
|
||||
}
|
||||
|
||||
World worldInstance = Bukkit.getWorld( world.getAsString() );
|
||||
if (worldInstance == null) {
|
||||
throw new IllegalArgumentException("Unknown/not loaded world");
|
||||
}
|
||||
|
||||
return new Location( worldInstance, x.getAsDouble(), y.getAsDouble(), z.getAsDouble(), yaw.getAsFloat(), pitch.getAsFloat() );
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize( Location location, Type type, JsonSerializationContext jsonSerializationContext ) {
|
||||
|
||||
final JsonObject obj = new JsonObject();
|
||||
obj.addProperty( "world", location.getWorld().getName() );
|
||||
obj.addProperty( "x", location.getX() );
|
||||
obj.addProperty( "y", location.getY() );
|
||||
obj.addProperty( "z", location.getZ() );
|
||||
obj.addProperty( "yaw", location.getYaw() );
|
||||
obj.addProperty( "pitch", location.getPitch() );
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package us.tastybento.bskyblock.database.mysqljson;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import us.tastybento.bskyblock.database.DatabaseConnecter;
|
||||
import us.tastybento.bskyblock.database.DatabaseConnectionSettingsImpl;
|
||||
|
||||
public class MySQLDatabaseConnecterJ implements DatabaseConnecter {
|
||||
|
||||
private String connectionUrl;
|
||||
private DatabaseConnectionSettingsImpl dbSettings;
|
||||
private Connection connection = null;
|
||||
|
||||
/**
|
||||
* Class for MySQL database connections using the settings provided
|
||||
* @param dbSettings
|
||||
*/
|
||||
public MySQLDatabaseConnecterJ(DatabaseConnectionSettingsImpl dbSettings) {
|
||||
this.dbSettings = dbSettings;
|
||||
try {
|
||||
Class.forName("com.mysql.jdbc.Driver").newInstance();
|
||||
} catch (Exception e) {
|
||||
Bukkit.getLogger().severe("Could not instantiate JDBC driver! " + e.getMessage());
|
||||
}
|
||||
// jdbc:mysql://localhost:3306/Peoples?autoReconnect=true&useSSL=false
|
||||
connectionUrl = "jdbc:mysql://" + dbSettings.getHost() + "/" + dbSettings.getDatabaseName() + "?autoReconnect=true&useSSL=false&allowMultiQueries=true";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection createConnection() {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId(String tableName) {
|
||||
// Not used
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration loadYamlFile(String string, String key) {
|
||||
// Not used
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean uniqueIdExists(String tableName, String key) {
|
||||
// Not used
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveYamlFile(YamlConfiguration yamlConfig, String tableName, String fileName,
|
||||
Map<String, String> commentMap) {
|
||||
// Not used
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package us.tastybento.bskyblock.database.mysqljson;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import us.tastybento.bskyblock.database.DatabaseConnecter;
|
||||
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class that inserts a <T> into the corresponding database-table.
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class MySQLDatabaseHandlerJ<T> extends AbstractDatabaseHandler<T> {
|
||||
|
||||
/**
|
||||
* Connection to the database
|
||||
*/
|
||||
private Connection connection = null;
|
||||
|
||||
/**
|
||||
* Handles the connection to the database and creation of the initial database schema (tables) for
|
||||
* the class that will be stored.
|
||||
* @param plugin - BSkyBlock plugin object
|
||||
* @param type - the type of class to be stored in the database. Must inherit DataObject
|
||||
* @param databaseConnecter - authentication details for the database
|
||||
*/
|
||||
public MySQLDatabaseHandlerJ(Plugin plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
|
||||
super(plugin, type, databaseConnecter);
|
||||
connection = databaseConnecter.createConnection();
|
||||
// Check if the table exists in the database and if not, create it
|
||||
createSchema();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the table in the database if it doesn't exist already
|
||||
*/
|
||||
private void createSchema() {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("CREATE TABLE IF NOT EXISTS `");
|
||||
sql.append(dataObject.getCanonicalName());
|
||||
sql.append("` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), INDEX i (uniqueId) );");
|
||||
// Prepare and execute the database statements
|
||||
try (PreparedStatement pstmt = connection.prepareStatement(sql.toString())) {
|
||||
pstmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().severe(() -> "Problem trying to create schema for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> loadObjects() {
|
||||
List<T> list = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT `json` FROM `");
|
||||
sb.append(dataObject.getCanonicalName());
|
||||
sb.append("`");
|
||||
try (Statement preparedStatement = connection.createStatement()) {
|
||||
try (ResultSet resultSet = preparedStatement.executeQuery(sb.toString())) {
|
||||
// Load all the results
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.registerTypeAdapter(Location.class, new LocationAdapter()) ;
|
||||
Gson gson = builder.create();
|
||||
while (resultSet.next()) {
|
||||
list.add(gson.fromJson(resultSet.getString("json"), dataObject));
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().severe(() -> "Could not load objects " + e.getMessage());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T loadObject(String uniqueId) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT `json` FROM `");
|
||||
sb.append(dataObject.getCanonicalName());
|
||||
sb.append("` WHERE uniqueId = ? LIMIT 1");
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sb.toString())) {
|
||||
preparedStatement.setString(1, uniqueId);
|
||||
try (ResultSet resultSet = preparedStatement.executeQuery()) {
|
||||
while (resultSet.next()) {
|
||||
// If there is a result, we only want/need the first one
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.registerTypeAdapter(Location.class, new LocationAdapter()) ;
|
||||
Gson gson = builder.create();
|
||||
return gson.fromJson(resultSet.getString("json"), dataObject);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().severe(() -> "Could not load object " + uniqueId + " " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveObject(T instance) {
|
||||
Bukkit.getLogger().severe(() -> "Saving object " + instance.getClass().getName());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// Replace into is used so that any data in the table will be replaced with updated data
|
||||
sb.append("REPLACE INTO ");
|
||||
sb.append("`");
|
||||
// The table name is the canonical name, so that add-ons can be sure of a unique table in the database
|
||||
sb.append(dataObject.getCanonicalName());
|
||||
sb.append("` (json) VALUES (?)");
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sb.toString())) {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.registerTypeAdapter(Location.class, new LocationAdapter()) ;
|
||||
Gson gson = builder.create();
|
||||
preparedStatement.setString(1, gson.toJson(instance));
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().severe(() -> "Could not save object " + instance.getClass().getName() + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(T instance) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("DELETE FROM `");
|
||||
sb.append(dataObject.getCanonicalName());
|
||||
sb.append("` WHERE uniqueId = ?");
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(sb.toString())) {
|
||||
Method getUniqueId = dataObject.getMethod("getUniqueId");
|
||||
String uniqueId = (String) getUniqueId.invoke(instance);
|
||||
preparedStatement.setString(1, uniqueId);
|
||||
preparedStatement.executeQuery();
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe(() -> "Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#objectExists(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean objectExists(String key) {
|
||||
// Create the query to see if this key exists
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("SELECT IF ( EXISTS( SELECT * FROM `");
|
||||
query.append(dataObject.getCanonicalName());
|
||||
query.append("` WHERE `uniqueId` = ?), 1, 0)");
|
||||
|
||||
try (PreparedStatement preparedStatement = connection.prepareStatement(query.toString())) {
|
||||
preparedStatement.setString(1, key);
|
||||
try (ResultSet resultSet = preparedStatement.executeQuery()) {
|
||||
if (resultSet.next()) {
|
||||
return resultSet.getBoolean(1);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().severe("Could not check if key exists in database! " + key + " " + e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSettings(T instance)
|
||||
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
|
||||
// This method should not be used because configs are not stored in MySQL
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public T loadSettings(String uniqueId, T dbConfig) {
|
||||
// This method should not be used because configs are not stored in MySQL
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
22
src/main/java/us/tastybento/bskyblock/database/mysqljson/MySQLDatabaseJ.java
Executable file
22
src/main/java/us/tastybento/bskyblock/database/mysqljson/MySQLDatabaseJ.java
Executable file
@ -0,0 +1,22 @@
|
||||
package us.tastybento.bskyblock.database.mysqljson;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.database.BSBDatabase;
|
||||
import us.tastybento.bskyblock.database.DatabaseConnectionSettingsImpl;
|
||||
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
|
||||
|
||||
public class MySQLDatabaseJ extends BSBDatabase{
|
||||
|
||||
@Override
|
||||
public AbstractDatabaseHandler<?> getHandler(Class<?> type) {
|
||||
BSkyBlock plugin = BSkyBlock.getInstance();
|
||||
return new MySQLDatabaseHandlerJ<>(plugin, type, new MySQLDatabaseConnecterJ(new DatabaseConnectionSettingsImpl(
|
||||
plugin.getSettings().getDbHost(),
|
||||
plugin.getSettings().getDbPort(),
|
||||
plugin.getSettings().getDbName(),
|
||||
plugin.getSettings().getDbUsername(),
|
||||
plugin.getSettings().getDbPassword()
|
||||
)));
|
||||
}
|
||||
|
||||
}
|
@ -18,13 +18,13 @@ import us.tastybento.bskyblock.BSkyBlock;
|
||||
* @author tastybento
|
||||
*/
|
||||
public class Players implements DataObject {
|
||||
private Map<Integer, Location> homeLocations;
|
||||
private Map<Integer, Location> homeLocations = new HashMap<>();
|
||||
private String uniqueId;
|
||||
private String playerName;
|
||||
private int resetsLeft;
|
||||
private String locale = "";
|
||||
private int deaths;
|
||||
private Map<Location, Long> kickedList;
|
||||
private Map<Location, Long> kickedList = new HashMap<>();
|
||||
|
||||
/**
|
||||
* This is required for database storage
|
||||
|
@ -0,0 +1,109 @@
|
||||
package us.tastybento.bskyblock.database.mysqljson;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.Settings;
|
||||
import us.tastybento.bskyblock.database.mysql.MySQLDatabaseConnecter;
|
||||
import us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandlerTestDataObject;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
public class MySQLDatabaseHandlerJTest {
|
||||
|
||||
private static MySQLDatabaseHandlerJ<MySQLDatabaseHandlerTestDataObject> handler;
|
||||
private static MySQLDatabaseHandlerTestDataObject instance;
|
||||
private static String UNIQUE_ID = "xyz";
|
||||
private static MySQLDatabaseConnecter dbConn;
|
||||
private static World world;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws Exception {
|
||||
Server server = mock(Server.class);
|
||||
world = mock(World.class);
|
||||
when(server.getLogger()).thenReturn(Logger.getAnonymousLogger());
|
||||
when(server.getWorld("world")).thenReturn(world);
|
||||
when(server.getVersion()).thenReturn("BSB_Mocking");
|
||||
|
||||
PluginManager pluginManager = mock(PluginManager.class);
|
||||
when(server.getPluginManager()).thenReturn(pluginManager);
|
||||
|
||||
ItemFactory itemFactory = mock(ItemFactory.class);
|
||||
when(server.getItemFactory()).thenReturn(itemFactory);
|
||||
|
||||
Bukkit.setServer(server);
|
||||
|
||||
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
|
||||
|
||||
BSkyBlock plugin = mock(BSkyBlock.class);
|
||||
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
|
||||
dbConn = mock(MySQLDatabaseConnecter.class);
|
||||
Connection connection = mock(Connection.class);
|
||||
when(dbConn.createConnection()).thenReturn(connection);
|
||||
PreparedStatement ps = mock(PreparedStatement.class);
|
||||
when(connection.prepareStatement(Mockito.anyString())).thenReturn(ps);
|
||||
Statement statement = mock(Statement.class);
|
||||
when(connection.createStatement()).thenReturn(statement);
|
||||
ResultSet rs = mock(ResultSet.class);
|
||||
when(ps.executeQuery()).thenReturn(rs);
|
||||
when(statement.executeQuery(Mockito.anyString())).thenReturn(rs);
|
||||
instance = new MySQLDatabaseHandlerTestDataObject();
|
||||
instance.setUniqueId(UNIQUE_ID);
|
||||
handler = new MySQLDatabaseHandlerJ<>(plugin, MySQLDatabaseHandlerTestDataObject.class, dbConn);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveObject() {
|
||||
handler.saveObject(instance);
|
||||
BSkyBlock plugin = mock(BSkyBlock.class);
|
||||
Settings settings = mock(Settings.class);
|
||||
when(plugin.getSettings()).thenReturn(settings);
|
||||
when(settings.getDeathsMax()).thenReturn(10);
|
||||
Players players = new Players();
|
||||
players.setUniqueId(UUID.randomUUID().toString());
|
||||
players.setDeaths(23);
|
||||
Location location = mock(Location.class);
|
||||
Mockito.when(location.getWorld()).thenReturn(world);
|
||||
Mockito.when(location.getBlockX()).thenReturn(0);
|
||||
Mockito.when(location.getBlockY()).thenReturn(0);
|
||||
Mockito.when(location.getBlockZ()).thenReturn(0);
|
||||
|
||||
players.setHomeLocation(location);
|
||||
players.setHomeLocation(location, 1);
|
||||
players.setHomeLocation(location, 2);
|
||||
Map<Location, Long> map = new HashMap<>();
|
||||
map.put(location, 324L);
|
||||
players.setKickedList(map);
|
||||
players.setLocale("sdfsd");
|
||||
players.setPlayerName("name");
|
||||
players.setPlayerUUID(UUID.randomUUID());
|
||||
players.setResetsLeft(3);
|
||||
|
||||
MySQLDatabaseHandlerJ<Players> h = new MySQLDatabaseHandlerJ<>(plugin, Players.class, dbConn);
|
||||
h.saveObject(players);
|
||||
}
|
||||
|
||||
}
|
276
src/test/java/us/tastybento/bskyblock/database/mysqljson/Players.java
Executable file
276
src/test/java/us/tastybento/bskyblock/database/mysqljson/Players.java
Executable file
@ -0,0 +1,276 @@
|
||||
package us.tastybento.bskyblock.database.mysqljson;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.database.objects.DataObject;
|
||||
|
||||
/**
|
||||
* Tracks the following info on the player
|
||||
*
|
||||
* @author tastybento
|
||||
*/
|
||||
public class Players implements DataObject {
|
||||
private Map<Integer, Location> homeLocations = new HashMap<>();
|
||||
private String uniqueId;
|
||||
private String playerName;
|
||||
private int resetsLeft;
|
||||
private String locale = "";
|
||||
private int deaths;
|
||||
private Map<Location, Long> kickedList = new HashMap<>();
|
||||
|
||||
/**
|
||||
* This is required for database storage
|
||||
*/
|
||||
public Players() {}
|
||||
|
||||
/**
|
||||
* @param plugin - BSkyBlock plugin object
|
||||
* @param uniqueId - unique ID
|
||||
* Constructor - initializes the state variables
|
||||
*
|
||||
*/
|
||||
public Players(BSkyBlock plugin, final UUID uniqueId) {
|
||||
this.uniqueId = uniqueId.toString();
|
||||
homeLocations = new HashMap<>();
|
||||
playerName = "";
|
||||
resetsLeft = plugin.getSettings().getResetLimit();
|
||||
locale = "";
|
||||
kickedList = new HashMap<>();
|
||||
playerName = Bukkit.getServer().getOfflinePlayer(uniqueId).getName();
|
||||
if (playerName == null) {
|
||||
playerName = uniqueId.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default home location.
|
||||
* @return Location
|
||||
*/
|
||||
public Location getHomeLocation() {
|
||||
return getHomeLocation(1); // Default
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the home location by number.
|
||||
* @param number - a number
|
||||
* @return Location of this home or null if not available
|
||||
*/
|
||||
public Location getHomeLocation(int number) {
|
||||
/*
|
||||
Bukkit.getLogger().info("DEBUG: getting home location " + number);
|
||||
|
||||
Bukkit.getLogger().info("DEBUG: " + homeLocations.toString());
|
||||
for (Entry<Integer, Location> en : homeLocations.entrySet()) {
|
||||
Bukkit.getLogger().info("DEBUG: " + en.getKey() + " ==> " + en.getValue());
|
||||
if (number == en.getKey())
|
||||
Bukkit.getLogger().info("DEBUG: key = number");
|
||||
}*/
|
||||
return homeLocations.get(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of home locations
|
||||
*/
|
||||
public Map<Integer,Location> getHomeLocations() {
|
||||
return homeLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the kickedList
|
||||
*/
|
||||
public Map<Location, Long> getKickedList() {
|
||||
return kickedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kickedList the kickedList to set
|
||||
*/
|
||||
public void setKickedList(Map<Location, Long> kickedList) {
|
||||
this.kickedList = kickedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param homeLocations the homeLocations to set
|
||||
*/
|
||||
public void setHomeLocations(Map<Integer, Location> homeLocations) {
|
||||
//Bukkit.getLogger().info("DEBUG: " + homeLocations.toString());
|
||||
this.homeLocations = homeLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerName the playerName to set
|
||||
*/
|
||||
public void setPlayerName(String playerName) {
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return Bukkit.getPlayer(UUID.fromString(uniqueId));
|
||||
}
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
return UUID.fromString(uniqueId);
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the resetsLeft
|
||||
*/
|
||||
public int getResetsLeft() {
|
||||
return resetsLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resetsLeft
|
||||
* the resetsLeft to set
|
||||
*/
|
||||
public void setResetsLeft(int resetsLeft) {
|
||||
this.resetsLeft = resetsLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the home location of the player in a String format
|
||||
*
|
||||
* @param l
|
||||
* a Bukkit location
|
||||
*/
|
||||
public void setHomeLocation(final Location l) {
|
||||
setHomeLocation(l, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the numbered home location of the player. Numbering starts at 1.
|
||||
* @param location - the location
|
||||
* @param number - a number
|
||||
*/
|
||||
public void setHomeLocation(final Location location, int number) {
|
||||
if (location == null) {
|
||||
homeLocations.clear();
|
||||
} else {
|
||||
homeLocations.put(number, location);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the uuid for this player object
|
||||
* @param uuid - UUID
|
||||
*/
|
||||
public void setPlayerUUID(final UUID uuid) {
|
||||
uniqueId = uuid.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all home Locations
|
||||
*/
|
||||
public void clearHomeLocations() {
|
||||
homeLocations.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the locale
|
||||
*/
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param locale the locale to set
|
||||
*/
|
||||
public void setLocale(String locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deaths
|
||||
*/
|
||||
public int getDeaths() {
|
||||
return deaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deaths the deaths to set
|
||||
*/
|
||||
public void setDeaths(int deaths) {
|
||||
this.deaths = deaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add death
|
||||
*/
|
||||
public void addDeath() {
|
||||
deaths++;
|
||||
if (deaths > getPlugin().getSettings().getDeathsMax()) {
|
||||
deaths = getPlugin().getSettings().getDeathsMax();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can invite or still waiting for cool down to end
|
||||
*
|
||||
* @param location - the location
|
||||
* to check
|
||||
* @return number of mins/hours left until cool down ends
|
||||
*/
|
||||
public long getInviteCoolDownTime(Location location) {
|
||||
// Check the hashmap
|
||||
if (location != null && kickedList.containsKey(location)) {
|
||||
// plugin.getLogger().info("DEBUG: Location is known");
|
||||
// The location is in the list
|
||||
// Check the date/time
|
||||
Date kickedDate = new Date(kickedList.get(location));
|
||||
// plugin.getLogger().info("DEBUG: kicked date = " + kickedDate);
|
||||
Calendar coolDownTime = Calendar.getInstance();
|
||||
coolDownTime.setTime(kickedDate);
|
||||
// coolDownTime.add(Calendar.HOUR_OF_DAY, Settings.inviteWait);
|
||||
coolDownTime.add(Calendar.MINUTE, getPlugin().getSettings().getInviteWait());
|
||||
// Add the invite cooldown period
|
||||
Calendar timeNow = Calendar.getInstance();
|
||||
// plugin.getLogger().info("DEBUG: date now = " + timeNow);
|
||||
if (coolDownTime.before(timeNow)) {
|
||||
// The time has expired
|
||||
kickedList.remove(location);
|
||||
return 0;
|
||||
} else {
|
||||
// Still not there yet
|
||||
// long hours = (coolDownTime.getTimeInMillis() -
|
||||
// timeNow.getTimeInMillis())/(1000 * 60 * 60);
|
||||
// Temp minutes
|
||||
return (coolDownTime.getTimeInMillis() - timeNow.getTimeInMillis()) / (1000 * 60);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the invite cooldown timer for location. Location should be the center of an island.
|
||||
* @param location - the location
|
||||
*/
|
||||
public void startInviteCoolDownTimer(Location location) {
|
||||
if (location != null) {
|
||||
kickedList.put(location, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUniqueId(String uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user