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:
Tastybento 2018-02-28 08:38:56 -08:00
parent e598fa7c93
commit fcede01a11
13 changed files with 816 additions and 121 deletions

View File

@ -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,8 +24,10 @@ public abstract class BSBDatabase {
public enum DatabaseType{
FLATFILE(new FlatFileDatabase()),
MYSQL(new MySQLDatabase());
MYSQL(new MySQLDatabase()),
//JSON();
MYSQLJ(new MySQLDatabaseJ());
BSBDatabase database;
DatabaseType(BSBDatabase database){

View File

@ -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)
*/

View File

@ -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>

View File

@ -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);
}
/**

View File

@ -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);

View File

@ -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,46 +738,45 @@ 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()) {

View File

@ -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;
}
}

View File

@ -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
}
}

View File

@ -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;
}
}

View 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()
)));
}
}

View File

@ -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

View File

@ -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);
}
}

View 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;
}
}