Fixed merge conflicts.

This commit is contained in:
tastybento 2018-03-12 05:11:02 +09:00
commit 8e97186caf
35 changed files with 538 additions and 1540 deletions

View File

@ -1,6 +1,19 @@
# Source language and JDK version to use.
language: java
jdk: oraclejdk8
sudo: false
install: true
before_install:
- sed -i.bak -e 's|https://nexus.codehaus.org/snapshots/|https://oss.sonatype.org/content/repositories/codehaus-snapshots/|g' ~/.m2/settings.xml
- sed -i.bak -e 's|https://nexus.codehaus.org/snapshots/|https://oss.sonatype.org/content/repositories/codehaus-snapshots/|g'
~/.m2/settings.xml
addons:
sonarcloud:
organization: "tastybento-github"
token:
secure: "uJDH+Af1VSjvaOLOmA5KPofLnfqD7Y4j6bWnQ+mwuaJfOCG6D1SYeXg6LuBCLX2yXc9Li3fDQRxu9Xp521ph3kCfbeJLhQTMxoVDIS+3KY4FXrc+zEdg6G7hRsDD2iGCRtZjI52O7NdwWxUqftXIUFJjYoL0H2zJGJzF85dxOXFtve5CGIPkuvnZp+mUim+b0LBUpV1xjBU/8I0Q121FXxp0GH3Wi0SiAoU484bjOtbjEFvuJvVru45WtikJOKKabrxO5uoKqHPrjKdkkRrvKw6fBMpQ5b+/kXR3OWvi9Ap0IWKMkBQBq4R7xhaIVQVIkfwTPg6rl21nLKYHl679HzqpAozxR1CsDs9dXDj22ERRjjp9rKT5O1UHifCmLgOtB+hRKSDhipOayqRnxRhMYOzvniDcZ0Dr4jgsstY7VG2TFtuX7yLb//SqV+41XuClmtvX69vRD+iL5v0FR52ymf8x43ZnouxT+iAcLrfsm7ICOP8FmOQSGi0NkRhKc+6f+STy47kHzZgdzlQqJtmP6s7eXoGtOv4RuPlMoFMXyOba7SYtcxbUgg7dKiL4iHRB4+GX46uWl1hilWKCbkZrv6/u9SZsOQXwMC409qG5/G7aRC1ZZ/vlCMZz8+/QbNHGO0enhzeKD5mkZy6coi/c/9gYK0eXV0+s/gXHU9hx5v4="
jdk:
- oraclejdk8
script:
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.sonar/cache'

View File

@ -8,8 +8,6 @@ import us.tastybento.bskyblock.api.user.Notifier;
import us.tastybento.bskyblock.commands.AdminCommand;
import us.tastybento.bskyblock.commands.IslandCommand;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.managers.PlayersManager;
import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.generators.IslandWorld;
import us.tastybento.bskyblock.listeners.JoinLeaveListener;
import us.tastybento.bskyblock.listeners.NetherPortals;
@ -17,7 +15,9 @@ import us.tastybento.bskyblock.listeners.PanelListenerManager;
import us.tastybento.bskyblock.managers.AddonsManager;
import us.tastybento.bskyblock.managers.CommandsManager;
import us.tastybento.bskyblock.managers.FlagsManager;
import us.tastybento.bskyblock.managers.IslandsManager;
import us.tastybento.bskyblock.managers.LocalesManager;
import us.tastybento.bskyblock.managers.PlayersManager;
import us.tastybento.bskyblock.managers.RanksManager;
/**
@ -27,7 +27,7 @@ import us.tastybento.bskyblock.managers.RanksManager;
*/
public class BSkyBlock extends JavaPlugin {
private static BSkyBlock plugin;
private static BSkyBlock instance;
// Databases
private PlayersManager playersManager;
@ -77,7 +77,7 @@ public class BSkyBlock extends JavaPlugin {
ranksManager = new RanksManager(this);
// Load metrics
metrics = new Metrics(plugin);
metrics = new Metrics(instance);
registerCustomCharts();
// Load Notifier
@ -93,29 +93,29 @@ public class BSkyBlock extends JavaPlugin {
// at this point. Therefore, the 1 tick scheduler is required.
getServer().getScheduler().runTask(this, () -> {
// Create the world if it does not exist
islandWorldManager = new IslandWorld(plugin);
islandWorldManager = new IslandWorld(instance);
getServer().getScheduler().runTask(plugin, () -> {
getServer().getScheduler().runTask(instance, () -> {
// Load Flags
flagsManager = new FlagsManager(plugin);
flagsManager = new FlagsManager(instance);
// Load islands from database
islandsManager.load();
localesManager = new LocalesManager(plugin);
PlaceholderHandler.register(plugin);
localesManager = new LocalesManager(instance);
PlaceholderHandler.register(instance);
// Register Listeners
registerListeners();
// Load addons
addonsManager = new AddonsManager(plugin);
addonsManager = new AddonsManager(instance);
addonsManager.enableAddons();
// Save islands & players data asynchronously every X minutes
getSettings().setDatabaseBackupPeriod(10 * 60 * 20);
plugin.getServer().getScheduler().runTaskTimer(plugin, () -> {
instance.getServer().getScheduler().runTaskTimer(instance, () -> {
playersManager.save(true);
islandsManager.save(true);
}, getSettings().getDatabaseBackupPeriod(), getSettings().getDatabaseBackupPeriod());
@ -199,11 +199,11 @@ public class BSkyBlock extends JavaPlugin {
}
private static void setInstance(BSkyBlock plugin) {
BSkyBlock.plugin = plugin;
BSkyBlock.instance = plugin;
}
public static BSkyBlock getInstance() {
return plugin;
return instance;
}
/**

View File

@ -15,8 +15,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.Listener;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.managers.PlayersManager;
import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.managers.IslandsManager;
import us.tastybento.bskyblock.managers.PlayersManager;
/**
* Add-on class for BSkyBlock. Extend this to create an add-on. The operation

View File

@ -20,8 +20,8 @@ import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.Settings;
import us.tastybento.bskyblock.api.events.command.CommandEvent;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.database.managers.PlayersManager;
import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.managers.IslandsManager;
import us.tastybento.bskyblock.managers.PlayersManager;
import us.tastybento.bskyblock.util.Util;
/**

View File

@ -9,8 +9,8 @@ import java.util.logging.Logger;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.addons.Addon;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
/**
* Handy config class to store and load Java POJOs as YAML configs
@ -90,4 +90,4 @@ public class BSBConfig<T> {
}
}
}

View File

@ -4,9 +4,10 @@ import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.flatfile.ConfigHandler;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
/**
* Simple interface for tagging all classes containing ConfigEntries.
@ -21,7 +22,7 @@ public interface ISettings<T> {
@SuppressWarnings("unchecked")
default void saveSettings() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException, SQLException {
// Get the handler
AbstractDatabaseHandler<T> settingsHandler = (AbstractDatabaseHandler<T>) new FlatFileDatabase().getHandler(getInstance().getClass());
ConfigHandler<T> settingsHandler = (ConfigHandler<T>) new FlatFileDatabase().getConfig(getInstance().getClass());
// Load every field in the config class
settingsHandler.saveSettings(getInstance());
}
@ -44,7 +45,7 @@ public interface ISettings<T> {
dbConfig = dbhandler.loadObject(getUniqueId());
}
// Get the handler
AbstractDatabaseHandler<T> configHandler = (AbstractDatabaseHandler<T>) new FlatFileDatabase().getHandler(getInstance().getClass());
ConfigHandler<T> configHandler = (ConfigHandler<T> ) new FlatFileDatabase().getConfig(getInstance().getClass());
// Load every field in the config class
return configHandler.loadSettings(getUniqueId(), dbConfig);
}

View File

@ -1,6 +1,9 @@
package us.tastybento.bskyblock.api.panels.builders;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Material;

View File

@ -11,7 +11,7 @@ import us.tastybento.bskyblock.api.commands.CompositeCommand;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.api.events.island.IslandEvent.Reason;
import us.tastybento.bskyblock.commands.IslandCommand;
import us.tastybento.bskyblock.database.managers.island.NewIsland;
import us.tastybento.bskyblock.managers.island.NewIsland;
/**
* /island create - Create an island.

View File

@ -10,8 +10,8 @@ import us.tastybento.bskyblock.Constants;
import us.tastybento.bskyblock.api.commands.CompositeCommand;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.api.events.island.IslandEvent.Reason;
import us.tastybento.bskyblock.database.managers.island.NewIsland;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.managers.island.NewIsland;
public class IslandResetCommand extends CompositeCommand {

View File

@ -1,4 +1,4 @@
package us.tastybento.bskyblock.database.managers;
package us.tastybento.bskyblock.database;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
@ -7,8 +7,6 @@ import java.util.List;
import org.bukkit.plugin.Plugin;
import us.tastybento.bskyblock.database.DatabaseConnecter;
/**
* An abstract class that handles insert/select-operations into/from a database
*
@ -30,12 +28,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 +45,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>
@ -101,18 +81,4 @@ public abstract class AbstractDatabaseHandler<T> {
*/
public abstract boolean objectExists(String key);
/**
* Saves a file as settings
* @param instance
*/
public abstract void saveSettings(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException;
/**
* Loads a file as settings
* @param uniqueId - unique ID
* @param dbConfig - the database mirror of this object. It will be checked against what is loaded to see if any significant changes have been made
* @return Settings object
*/
public abstract T loadSettings(String uniqueId, T dbConfig) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IntrospectionException;
}

View File

@ -2,7 +2,6 @@ package us.tastybento.bskyblock.database;
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;
public abstract class BSBDatabase {
@ -24,7 +23,7 @@ public abstract class BSBDatabase {
public enum DatabaseType{
FLATFILE(new FlatFileDatabase()),
MYSQL(new MySQLDatabase());
BSBDatabase database;
DatabaseType(BSBDatabase database){

View File

@ -0,0 +1,39 @@
package us.tastybento.bskyblock.database.flatfile;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import org.bukkit.plugin.Plugin;
import us.tastybento.bskyblock.database.DatabaseConnecter;
/**
* Class handles config settings saving and loading
*
* @author tastybento
*
* @param <T> Handles config files for Class <T>
*/
public class ConfigHandler<T> extends FlatFileDatabaseHandler<T> {
public ConfigHandler(Plugin plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
super(plugin, type, databaseConnecter);
}
public void saveSettings(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
configFlag = true;
saveObject(instance);
}
public T loadSettings(String uniqueId, T dbConfig) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IntrospectionException {
if (dbConfig == null) {
return loadObject(uniqueId);
}
// TODO: compare the loaded with the database copy
return loadObject(uniqueId);
}
}

View File

@ -1,8 +1,8 @@
package us.tastybento.bskyblock.database.flatfile;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
public class FlatFileDatabase extends BSBDatabase{
@ -10,5 +10,14 @@ public class FlatFileDatabase extends BSBDatabase{
public AbstractDatabaseHandler<?> getHandler(Class<?> type) {
return new FlatFileDatabaseHandler<>(BSkyBlock.getInstance(), type, new FlatFileDatabaseConnecter(BSkyBlock.getInstance(), null));
}
/**
* Get the config
* @param type - config object type
* @return - the config handler
*/
public AbstractDatabaseHandler<?> getConfig(Class<?> type) {
return new ConfigHandler<>(BSkyBlock.getInstance(), type, new FlatFileDatabaseConnecter(BSkyBlock.getInstance(), null));
}
}

View File

@ -31,8 +31,8 @@ import us.tastybento.bskyblock.Constants.GameType;
import us.tastybento.bskyblock.api.configuration.ConfigComment;
import us.tastybento.bskyblock.api.configuration.ConfigEntry;
import us.tastybento.bskyblock.api.configuration.StoreAt;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.DatabaseConnecter;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.objects.adapters.Adapter;
import us.tastybento.bskyblock.database.objects.adapters.AdapterInterface;
import us.tastybento.bskyblock.util.Util;
@ -50,25 +50,12 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
private static final String DATABASE_FOLDER_NAME = "database";
private static final boolean DEBUG = false;
private boolean configFlag;
protected boolean configFlag;
public FlatFileDatabaseHandler(Plugin plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
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)
*/
@ -277,15 +264,6 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
return instance;
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#saveConfig(java.lang.Object)
*/
@Override
public void saveSettings(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
configFlag = true;
saveObject(instance);
}
/**
* Inserts T into the corresponding database-table
*
@ -538,18 +516,4 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
}
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#loadSettings(java.lang.String, java.lang.Object)
*/
@Override
public T loadSettings(String uniqueId, T dbConfig) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IntrospectionException {
if (dbConfig == null) {
return loadObject(uniqueId);
}
// TODO: compare the loaded with the database copy
return loadObject(uniqueId);
}
}

View File

@ -1,9 +1,9 @@
package us.tastybento.bskyblock.database.mysql;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.DatabaseConnectionSettingsImpl;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
public class MySQLDatabase extends BSBDatabase{

View File

@ -1,42 +1,30 @@
package us.tastybento.bskyblock.database.mysql;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffectType;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.flags.Flag;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.DatabaseConnecter;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.objects.adapters.Adapter;
import us.tastybento.bskyblock.database.objects.adapters.AdapterInterface;
import us.tastybento.bskyblock.util.Util;
import us.tastybento.bskyblock.database.mysql.adapters.FlagAdapter;
import us.tastybento.bskyblock.database.mysql.adapters.LocationAdapter;
import us.tastybento.bskyblock.database.mysql.adapters.PotionEffectTypeAdapter;
import us.tastybento.bskyblock.database.mysql.adapters.WorldAdapter;
import us.tastybento.bskyblock.database.objects.DataObject;
/**
*
@ -52,47 +40,8 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
* Connection to the database
*/
private Connection connection = null;
/**
* This hashmap maps Java types to MySQL SQL types because they are not the same
*/
private static final HashMap<String, String> MYSQL_MAPPING = new HashMap<>();
private static final String STRING_MAP = "VARCHAR(254)";
static {
MYSQL_MAPPING.put(boolean.class.getTypeName(), "BOOL");
MYSQL_MAPPING.put(byte.class.getTypeName(), "TINYINT");
MYSQL_MAPPING.put(short.class.getTypeName(), "SMALLINT");
MYSQL_MAPPING.put(int.class.getTypeName(), "INTEGER");
MYSQL_MAPPING.put(long.class.getTypeName(), "BIGINT");
MYSQL_MAPPING.put(double.class.getTypeName(), "DOUBLE PRECISION");
MYSQL_MAPPING.put(Boolean.class.getTypeName(), "BOOL");
MYSQL_MAPPING.put(Byte.class.getTypeName(), "TINYINT");
MYSQL_MAPPING.put(Short.class.getTypeName(), "SMALLINT");
MYSQL_MAPPING.put(Integer.class.getTypeName(), "INTEGER");
MYSQL_MAPPING.put(Long.class.getTypeName(), "BIGINT");
MYSQL_MAPPING.put(Double.class.getTypeName(), "DOUBLE PRECISION");
MYSQL_MAPPING.put(BigDecimal.class.getTypeName(), "DECIMAL(13,0)");
MYSQL_MAPPING.put(String.class.getTypeName(), STRING_MAP);
MYSQL_MAPPING.put(Date.class.getTypeName(), "DATE");
MYSQL_MAPPING.put(Time.class.getTypeName(), "TIME");
MYSQL_MAPPING.put(Timestamp.class.getTypeName(), "TIMESTAMP");
MYSQL_MAPPING.put(UUID.class.getTypeName(), "VARCHAR(36)");
// Bukkit Mappings
MYSQL_MAPPING.put(Location.class.getTypeName(), STRING_MAP);
MYSQL_MAPPING.put(World.class.getTypeName(), STRING_MAP);
// Collections are stored as additional tables. The boolean indicates whether there
// is any data in it or not (maybe)
MYSQL_MAPPING.put(Set.class.getTypeName(), "BOOL");
MYSQL_MAPPING.put(Map.class.getTypeName(), "BOOL");
MYSQL_MAPPING.put(HashMap.class.getTypeName(), "BOOL");
MYSQL_MAPPING.put(ArrayList.class.getTypeName(), "BOOL");
// Enums
MYSQL_MAPPING.put(Enum.class.getTypeName(), STRING_MAP);
}
private BSkyBlock bskyblock;
/**
* Handles the connection to the database and creation of the initial database schema (tables) for
@ -101,13 +50,14 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
* @param type - the type of class to be stored in the database. Must inherit DataObject
* @param databaseConnecter - authentication details for the database
*/
public MySQLDatabaseHandler(Plugin plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
public MySQLDatabaseHandler(BSkyBlock plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
super(plugin, type, databaseConnecter);
this.bskyblock = plugin;
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
*/
@ -115,71 +65,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE IF NOT EXISTS `");
sql.append(dataObject.getCanonicalName());
sql.append("` (");
// Run through the fields of the class using introspection
for (Field field : dataObject.getDeclaredFields()) {
try {
// Get the description of the field
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Get default SQL mappings
// Get the write method for this field. This method will take an argument of the type of this field.
Method writeMethod = propertyDescriptor.getWriteMethod();
// The SQL column name is the name of the field
String columnName = field.getName();
// Get the mapping for this field from the hashmap
String typeName = propertyDescriptor.getPropertyType().getTypeName();
if (propertyDescriptor.getPropertyType().isEnum()) {
typeName = "Enum";
}
String mapping = MYSQL_MAPPING.get(typeName);
// If it exists, then create the SQL
if (mapping != null) {
// Note that the column name must be enclosed in `'s because it may include reserved words.
sql.append("`");
sql.append(columnName);
sql.append("` ");
sql.append(mapping);
sql.append(",");
// Create set and map tables if the type is a collection
if (propertyDescriptor.getPropertyType().equals(Set.class) ||
propertyDescriptor.getPropertyType().equals(Map.class) ||
propertyDescriptor.getPropertyType().equals(HashMap.class) ||
propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
// The ID in this table relates to the parent table and is unique
StringBuilder setSql = new StringBuilder();
setSql.append("CREATE TABLE IF NOT EXISTS `");
setSql.append(dataObject.getCanonicalName());
setSql.append(".");
setSql.append(field.getName());
setSql.append("` (");
setSql.append("uniqueId VARCHAR(36) NOT NULL, ");
// Get columns separated by commas
setSql.append(getCollectionColumnString(writeMethod,false,true));
// Close the SQL string
setSql.append(")");
// Execute the statement
try (PreparedStatement collections = connection.prepareStatement(setSql.toString())) {
collections.executeUpdate();
} catch (SQLException e) {
plugin.getLogger().severe(() -> "Getter or setter missing in data object. Cannot create schema! " + e.getMessage());
}
}
} else {
// The Java type is not in the hashmap, so we'll just guess that it can be stored in a string
// This should NOT be used in general because every type should be in the hashmap
sql.append(field.getName());
sql.append(" ");
sql.append(STRING_MAP);
sql.append(",");
plugin.getLogger().severe("Unknown type! Hoping it'll fit in a string!");
plugin.getLogger().severe(propertyDescriptor.getPropertyType().getTypeName());
}
} catch (IntrospectionException e) {
plugin.getLogger().severe(() -> "Getter or setter missing in data object. Cannot create schema! " + e.getMessage());
}
}
// For the main table for the class, the unique ID is the primary key
sql.append(" PRIMARY KEY (uniqueId))");
sql.append("` (json JSON, uniqueId VARCHAR(255) GENERATED ALWAYS AS (json->\"$.uniqueId\"), UNIQUE INDEX i (uniqueId) )");
// Prepare and execute the database statements
try (PreparedStatement pstmt = connection.prepareStatement(sql.toString())) {
pstmt.executeUpdate();
@ -187,631 +73,108 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
plugin.getLogger().severe(() -> "Problem trying to create schema for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
}
}
/**
* Creates a comma-separated-String with the names of the variables in this
* class
* Not used in Flat File database.
* @param usePlaceHolders
* true, if PreparedStatement-placeholders ('?') should be used
* instead of the names of the variables
* @return a comma-separated-String with the names of the variables
*/
public String getColumns(boolean usePlaceHolders) {
StringBuilder sb = new StringBuilder();
boolean first = true;
/* Iterate the column-names */
for (Field f : dataObject.getDeclaredFields()) {
if (first) {
first = false;
} else {
sb.append(", ");
}
if (usePlaceHolders) {
sb.append("?");
} else {
sb.append("`" + f.getName() + "`");
}
}
return sb.toString();
}
/**
* Returns a string of columns separated by commas that represent the parameter types of this method
* this is used to get into parameters like HashMap<Location, Boolean> at runtime and find out Location
* and Boolean.
* @param writeMethod
* @param usePlaceHolders
* true, if PreparedStatement-placeholders ('?') should be used
* instead of the names of the variables
* @param createSchema if true contains the columns types
* @return Returns a string of columns separated by commas.
*/
private String getCollectionColumnString(Method writeMethod, boolean usePlaceHolders, boolean createSchema) {
StringBuilder sb = new StringBuilder();
List<String> cols = getCollentionColumnList(writeMethod, createSchema);
boolean first = true;
for (String col : cols) {
// Add commas
if (first) {
first = false;
} else {
sb.append(", ");
}
// this is used if the string is going to be used to insert something so the value will replace the ?
if (usePlaceHolders) {
sb.append("?");
} else {
sb.append(col);
}
}
return sb.toString();
}
/**
* Returns a list of columns that represent the parameter types of this method
* @param method
* @param createSchema if true contains the columns types
* @return Returns a list of columns separated by commas.
*/
private List<String> getCollentionColumnList(Method method, boolean createSchema) {
List<String> columns = new ArrayList<>();
for (Entry<String,String> en : getCollectionColumnMap(method).entrySet()) {
StringBuilder col = new StringBuilder();
col.append(en.getKey());
if (createSchema) {
col.append(" ");
col.append(en.getValue());
}
columns.add(col.toString());
}
return columns;
}
/**
* Returns a map of column names and their types
* @param method
* @return
*/
private Map<String,String> getCollectionColumnMap(Method method) {
Map<String,String> columns = new LinkedHashMap<>();
// Get the return type
// This uses a trick to extract what the arguments are of the writeMethod of the field.
// In this way, we can deduce what type needs to be written at runtime.
Type[] genericParameterTypes = method.getGenericParameterTypes();
// There could be more than one argument, so step through them
for (Type genericParameterType : genericParameterTypes) {
// If the argument is a parameter, then do something - this should always be true if the parameter is a collection
if (genericParameterType instanceof ParameterizedType) {
// Get the actual type arguments of the parameter
Type[] parameters = ((ParameterizedType)genericParameterType).getActualTypeArguments();
//parameters[0] contains java.lang.String for method like "method(List<String> value)"
// Run through them one by one and create a SQL string
int index = 0;
for (Type type : parameters) {
// This is a request for column names.
String setMapping = MYSQL_MAPPING.get(type.getTypeName());
// This column name format is typeName_# where # is a number incremented from 0
columns.put("`" + type.getTypeName() + "_" + index + "`", setMapping != null ? setMapping : STRING_MAP);
// Increment the index so each column has a unique name
index++;
}
}
}
return columns;
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#createSelectQuery()
*/
@Override
protected String createSelectQuery() {
StringBuilder sb = new StringBuilder();
sb.append("SELECT ");
sb.append(getColumns(false));
sb.append(" FROM ");
sb.append("`");
sb.append(dataObject.getCanonicalName());
sb.append("`");
return sb.toString();
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#createInsertQuery()
*/
@Override
protected String createInsertQuery() {
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("`");
sb.append("(");
sb.append(getColumns(false));
sb.append(")");
sb.append(" VALUES (");
sb.append(getColumns(true));
sb.append(")");
return sb.toString();
// Gets the GSON builder
private Gson getGSON() {
// excludeFieldsWithoutExposeAnnotation - this means that every field to be stored should use @Expose
// enableComplexMapKeySerialization - forces GSON to use TypeAdapters even for Map keys
GsonBuilder builder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().enableComplexMapKeySerialization();
// Register adapters
builder.registerTypeAdapter(Location.class, new LocationAdapter(plugin)) ;
builder.registerTypeAdapter(World.class, new WorldAdapter(plugin));
builder.registerTypeAdapter(Flag.class, new FlagAdapter(bskyblock));
builder.registerTypeAdapter(PotionEffectType.class, new PotionEffectTypeAdapter());
// Keep null in the database
builder.serializeNulls();
// Allow characters like < or > without escaping them
builder.disableHtmlEscaping();
return builder.create();
}
@Override
protected String createDeleteQuery() {
return "DELETE FROM [table_name] WHERE uniqueId = ?";
}
/**
* 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)
*/
@Override
public void saveObject(T instance) throws SQLException,
SecurityException, IllegalArgumentException,
InstantiationException, IllegalAccessException,
IntrospectionException, InvocationTargetException, NoSuchMethodException {
// insertQuery is created in super from the createInsertQuery() method
try (PreparedStatement preparedStatement = connection.prepareStatement(insertQuery)) {
// 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();
final String uniqueId = (String) getUniqueId.invoke(instance);
if (uniqueId.isEmpty()) {
throw new SQLException("uniqueId is blank");
}
// Create the insertion
int i = 0;
// Run through the fields in the class using introspection
for (Field field : dataObject.getDeclaredFields()) {
// Get the field's property descriptor
propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Get the read method for this field
Method method = propertyDescriptor.getReadMethod();
//sql += "`" + field.getName() + "` " + mapping + ",";
// Invoke the read method to obtain the value from the class - this is the value we need to store in the database
Object value = method.invoke(instance);
// Adapter Notation
Adapter adapterNotation = field.getAnnotation(Adapter.class);
if (adapterNotation != null && AdapterInterface.class.isAssignableFrom(adapterNotation.value())) {
// A conversion adapter has been defined
value = ((AdapterInterface<?,?>)adapterNotation.value().newInstance()).deserialize(value);
}
// Create set and map table inserts if this is a Collection
if (propertyDescriptor.getPropertyType().equals(Set.class) ||
propertyDescriptor.getPropertyType().equals(Map.class) ||
propertyDescriptor.getPropertyType().equals(HashMap.class) ||
propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
// Collection
// The table is cleared for this uniqueId every time the data is stored
StringBuilder clearTableSql = new StringBuilder();
clearTableSql.append("DELETE FROM `");
clearTableSql.append(dataObject.getCanonicalName());
clearTableSql.append(".");
clearTableSql.append(field.getName());
clearTableSql.append("` WHERE uniqueId = ?");
try (PreparedStatement collStatement = connection.prepareStatement(clearTableSql.toString())) {
collStatement.setString(1, uniqueId);
collStatement.execute();
}
// Insert into the table
StringBuilder setSql = new StringBuilder();
setSql.append("INSERT INTO `");
setSql.append(dataObject.getCanonicalName());
setSql.append(".");
setSql.append(field.getName());
setSql.append("` (uniqueId, ");
// Get the columns we are going to insert, just the names of them
setSql.append(getCollectionColumnString(propertyDescriptor.getWriteMethod(), false, false));
setSql.append(") ");
// Get all the ?'s for the columns
setSql.append("VALUES (?,");
setSql.append(getCollectionColumnString(propertyDescriptor.getWriteMethod(), true, false));
setSql.append(")");
// Prepare the statement
try (PreparedStatement collStatement = connection.prepareStatement(setSql.toString())) {
// Set the uniqueId
collStatement.setString(1, uniqueId);
// Do single dimension types (set and list)
if (propertyDescriptor.getPropertyType().equals(Set.class) ||
propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
//plugin.getLogger().info("DEBUG: set class for ");
// Loop through the set or list
// Note that we have no idea what type this is
Collection<?> collection = (Collection<?>)value;
Iterator<?> it = collection.iterator();
while (it.hasNext()) {
Object setValue = it.next();
//if (setValue instanceof UUID) {
// Serialize everything
setValue = serialize(setValue, setValue.getClass());
//}
// Set the value from ? to whatever it is
collStatement.setObject(2, setValue);
// Execute the SQL in the database
collStatement.execute();
}
} else if (propertyDescriptor.getPropertyType().equals(Map.class) ||
propertyDescriptor.getPropertyType().equals(HashMap.class)) {
// Loop through the map
Map<?,?> collection = (Map<?,?>)value;
Iterator<?> it = collection.entrySet().iterator();
while (it.hasNext()) {
Entry<?,?> en = (Entry<?, ?>) it.next();
// Get the key and serialize it
Object key = serialize(en.getKey(), en.getKey().getClass());
// Get the value and serialize it
Object mapValue = serialize(en.getValue(), en.getValue().getClass());
// Write the objects into prepared statement
collStatement.setObject(2, key);
collStatement.setObject(3, mapValue);
// Write to database
collStatement.execute();
}
}
// Set value for the main insert. For collections, this is just a dummy value because the real values are in the
// additional table.
value = true;
}
} else {
// If the value is not a collection, it just needs to be serialized to go into the database.
value = serialize(value, propertyDescriptor.getPropertyType());
}
// Set the value in the main prepared statement and increment the location
// Note that with prepared statements, they count from 1, not 0, so the ++ goes on the front of i.
preparedStatement.setObject(++i, value);
}
// Add the statements to a batch
preparedStatement.addBatch();
// Execute
preparedStatement.executeBatch();
}
}
/**
* Serializes values if required to go into a database.
* TODO: This method will need expanding to include additional Java types
* @param value
* @param clazz - the known class of value
* @return the object to write to the database
*/
private Object serialize(Object value, Class<? extends Object> clazz) {
//plugin.getLogger().info("DEBUG: serialize - class is " + clazz.getTypeName());
if (value == null) {
// If the value is null to start, return null as a string
return "null";
}
// Types that need to be serialized
// TODO - add others, like Date, Timestamp, etc.
if (clazz.equals(UUID.class)) {
value = value.toString();
}
else
// Bukkit Types
if (clazz.equals(Location.class)) {
// Serialize
value = Util.getStringLocation(((Location)value));
} else
if (clazz.equals(World.class)) {
// Serialize - get the name
value = ((World)value).getName();
} else
if (clazz.getSuperclass() != null && clazz.getSuperclass().equals(Enum.class)) {
//Custom enums are a child of the Enum class. Just get the names of each one.
value = ((Enum<?>)value).name();
}
if (value == null) {
// The value could become null from the above checks
return "null";
}
return value;
}
/**
* Creates a list of <T>s filled with values from the corresponding
* database-table
*
* @return List of <T>s filled with values from the corresponding
* database-table
*
*/
@Override
public List<T> loadObjects() throws SQLException,
SecurityException, IllegalArgumentException,
InstantiationException, IllegalAccessException,
IntrospectionException, InvocationTargetException, ClassNotFoundException {
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(selectQuery)) {
return createObjects(resultSet);
}
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#selectObject(java.lang.String)
*/
@Override
public T loadObject(String uniqueId) throws InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException, IntrospectionException, SQLException, SecurityException, ClassNotFoundException {
// Build the select query
StringBuilder query = new StringBuilder();
query.append("SELECT ");
query.append(getColumns(false));
query.append(" FROM `");
query.append(dataObject.getCanonicalName());
query.append("` WHERE uniqueId = ? LIMIT 1");
try (PreparedStatement preparedStatement = connection.prepareStatement(query.toString())) {
preparedStatement.setString(1, uniqueId);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
// If there is a result, we only want/need the first one
List<T> result = createObjects(resultSet);
if (!result.isEmpty()) {
return result.get(0);
}
}
}
return null;
}
/**
*
* Creates a list of <T>s filled with values from the provided ResultSet
*
* @param resultSet
* ResultSet that contains the result of the
* database-select-query
*
* @return List of <T>s filled with values from the provided ResultSet
*
*/
@SuppressWarnings("unchecked")
private List<T> createObjects(ResultSet resultSet)
throws SecurityException, IllegalArgumentException,
SQLException, InstantiationException,
IllegalAccessException, IntrospectionException,
InvocationTargetException, ClassNotFoundException {
public List<T> loadObjects() {
List<T> list = new ArrayList<>();
// The database can return multiple results in one go, e.g., all the islands in the database
// Run through them one by one
while (resultSet.next()) {
// Create a new instance of this type
T instance = dataObject.newInstance();
// Get the unique ID from the results
String uniqueId = resultSet.getString("uniqueId");
if (uniqueId == null) {
throw new SQLException("No unique ID in the results!");
}
// Use introspection to run through all the fields in this type class
for (Field field : dataObject.getDeclaredFields()) {
/* We assume the table-column-names exactly match the variable-names of T */
Object value = resultSet.getObject(field.getName());
// Get the property descriptor of this type
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Get the write method for this field, because we are going to use it to write the value
// once we get the value from the database
Method method = propertyDescriptor.getWriteMethod();
// If the type is a Collection, then we need to deal with set and map tables
if (Collection.class.isAssignableFrom(propertyDescriptor.getPropertyType())
|| Map.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
// Collection
// value is just of type boolean right now
StringBuilder setSql = new StringBuilder();
setSql.append("SELECT ");
// Get the columns, just the names of them, no ?'s or types
setSql.append(getCollectionColumnString(method, false, false));
setSql.append(" ");
setSql.append("FROM `");
setSql.append(dataObject.getCanonicalName());
setSql.append(".");
setSql.append(field.getName());
setSql.append("` ");
// We will need to fill in the ? later with the unique id of the class from the database
setSql.append("WHERE uniqueId = ?");
// Prepare the statement
try (PreparedStatement collStatement = connection.prepareStatement(setSql.toString())) {
// Set the unique ID
collStatement.setObject(1, uniqueId);
try (ResultSet collectionResultSet = collStatement.executeQuery()) {
//plugin.getLogger().info("DEBUG: collectionResultSet = " + collectionResultSet.toString());
// Do single dimension types (set and list)
if (Set.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
// Loop through the collection resultset
// Note that we have no idea what type this is
List<Type> collectionTypes = Util.getCollectionParameterTypes(method);
// collectionTypes should be only 1 long
Type setType = collectionTypes.get(0);
value = new HashSet<>();
while (collectionResultSet.next()) {
((Set<Object>) value).add(deserialize(collectionResultSet.getObject(1),Class.forName(setType.getTypeName())));
}
} else if (List.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
// Loop through the collection resultset
// Note that we have no idea what type this is
List<Type> collectionTypes = Util.getCollectionParameterTypes(method);
// collectionTypes should be only 1 long
Type setType = collectionTypes.get(0);
value = new ArrayList<>();
//plugin.getLogger().info("DEBUG: collection type argument = " + collectionTypes);
while (collectionResultSet.next()) {
// Add to the list
((List<Object>) value).add(deserialize(collectionResultSet.getObject(1),Class.forName(setType.getTypeName())));
}
} else if (Map.class.isAssignableFrom(propertyDescriptor.getPropertyType()) ||
HashMap.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
// Loop through the collection resultset
// Note that we have no idea what type this is
List<Type> collectionTypes = Util.getCollectionParameterTypes(method);
// collectionTypes should be 2 long
Type keyType = collectionTypes.get(0);
Type valueType = collectionTypes.get(1);
value = new HashMap<>();
while (collectionResultSet.next()) {
// Work through the columns
// Key
Object key = deserialize(collectionResultSet.getObject(1),Class.forName(keyType.getTypeName()));
Object mapValue = deserialize(collectionResultSet.getObject(2),Class.forName(valueType.getTypeName()));
((Map<Object,Object>) value).put(key,mapValue);
}
} else {
// Set value for the main insert. For collections, this is just a dummy value because the real values are in the
// additional table.
value = true;
}
}
}
} else {
value = deserialize(value, propertyDescriptor.getPropertyType());
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
Gson gson = getGSON();
while (resultSet.next()) {
list.add(gson.fromJson(resultSet.getString("json"), dataObject));
}
// Adapter
// Check if there is an annotation on the field
Adapter adapterNotation = field.getAnnotation(Adapter.class);
if (adapterNotation != null && AdapterInterface.class.isAssignableFrom(adapterNotation.value())) {
// A conversion adapter has been defined
value = ((AdapterInterface<?,?>)adapterNotation.value().newInstance()).serialize(value);
}
// Write the value to the class
method.invoke(instance, value);
}
// Write the result into the list we are going to return
list.add(instance);
} catch (SQLException e) {
plugin.getLogger().severe(() -> "Could not load objects " + e.getMessage());
}
return list;
}
/**
* Deserialize any values according to their class
* TODO: expand to include additional types
* @param value
* @param clazz
* @return the deserialized value
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private Object deserialize(Object value, Class<? extends Object> clazz) {
if (value instanceof String && value.equals("null")) {
// If the value is null as a string, return null
return null;
}
// Types that need to be deserialized
if (clazz.equals(UUID.class)) {
value = UUID.fromString((String)value);
}
// Bukkit Types
if (clazz.equals(Location.class)) {
// Get Location from String - may be null...
value = Util.getLocationString(((String)value));
}
if (clazz.equals(World.class)) {
// Get world by name - may be null...
value = plugin.getServer().getWorld((String)value);
}
// Enums
if (Enum.class.isAssignableFrom(clazz)) {
//Custom enums are a child of the Enum class.
// Find out the value
try {
Class<Enum> enumClass = (Class<Enum>)clazz;
value = Enum.valueOf(enumClass, (String)value);
} catch (Exception e) {
plugin.getLogger().severe("Could not deserialize enum! " + e.getMessage());
}
}
return value;
}
/* (non-Javadoc)
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#deleteObject(java.lang.Object)
*/
@Override
public void deleteObject(T instance)
throws IllegalAccessException, IllegalArgumentException,
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();
}
// 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();
}
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
Gson gson = getGSON();
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) {
if (!(instance instanceof DataObject)) {
plugin.getLogger().severe(() -> "This class is not a DataObject: " + instance.getClass().getName());
return;
}
StringBuilder sb = new StringBuilder();
// Replace into is used so that any data in the table will be replaced with updated data
sb.append("INSERT 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 (?) ON DUPLICATE KEY UPDATE json = ?");
try (PreparedStatement preparedStatement = connection.prepareStatement(sb.toString())) {
Gson gson = getGSON();
String toStore = gson.toJson(instance);
preparedStatement.setString(1, toStore);
preparedStatement.setString(2, toStore);
preparedStatement.execute();
} catch (SQLException e) {
plugin.getLogger().severe(() -> "Could not save object " + instance.getClass().getName() + " " + e.getMessage());
}
}
@Override
public void deleteObject(T instance) {
if (!(instance instanceof DataObject)) {
plugin.getLogger().severe(() -> "This class is not a DataObject: " + instance.getClass().getName());
return;
}
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.execute();
} catch (Exception e) {
plugin.getLogger().severe(() -> "Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
}
}
/* (non-Javadoc)
@ -821,12 +184,11 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
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("SELECT IF ( EXISTS( SELECT * FROM `");
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()) {
@ -839,18 +201,4 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
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) throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IntrospectionException {
// This method should not be used because configs are not stored in MySQL
return null;
}
}

View File

@ -1,84 +0,0 @@
package us.tastybento.bskyblock.database.mysql;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.bukkit.Bukkit;
public class MySQLDatabaseResourceCloser {
/**
* Closes the provided ResultSets
*
* @param resultSets
* ResultSets that should be closed
*/
public static void close(ResultSet... resultSets) {
if (resultSets == null) {
return;
}
for (ResultSet resultSet : resultSets) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close MySQL resultset");
}
}
}
}
/**
* Closes the provided Statements
*
* @param statements
* Statements that should be closed
*/
public static void close(Statement... statements) {
/*
* No need to create methods for PreparedStatement and
* CallableStatement, because they extend Statement.
*/
if (statements == null) {
return;
}
for (Statement statement : statements) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close MySQL statement");
}
}
}
}
/**
* Closes the provided Connections
*
* @param connections
* Connections that should be closed
*/
public static void close(Connection... connections) {
if (connections == null) {
return;
}
for (Connection connection : connections) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
Bukkit.getLogger().severe("Could not close MySQL connection");
}
}
}
}
}

View File

@ -0,0 +1,39 @@
package us.tastybento.bskyblock.database.mysql.adapters;
import java.io.IOException;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.flags.Flag;
public class FlagAdapter extends TypeAdapter<Flag> {
private BSkyBlock plugin;
public FlagAdapter(BSkyBlock plugin) {
this.plugin = plugin;
}
@Override
public void write(JsonWriter out, Flag value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.value(value.getID());
}
@Override
public Flag read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
return plugin.getFlagsManager().getFlagByID(reader.nextString());
}
}

View File

@ -0,0 +1,54 @@
package us.tastybento.bskyblock.database.mysql.adapters;
import java.io.IOException;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
public class LocationAdapter extends TypeAdapter<Location> {
private Plugin plugin;
public LocationAdapter(Plugin plugin) {
this.plugin = plugin;
}
@Override
public void write(JsonWriter out, Location location) throws IOException {
if (location == null) {
out.nullValue();
return;
}
out.beginArray();
out.value(location.getWorld().getName());
out.value(location.getX());
out.value(location.getY());
out.value(location.getZ());
out.value(location.getYaw());
out.value(location.getPitch());
out.endArray();
}
@Override
public Location read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
in.beginArray();
World world = plugin.getServer().getWorld(in.nextString());
double x = in.nextDouble();
double y = in.nextDouble();
double z = in.nextDouble();
float yaw = (float)in.nextDouble();
float pitch = (float)in.nextDouble();
in.endArray();
return new Location(world, x, y, z, yaw, pitch);
}
}

View File

@ -0,0 +1,32 @@
package us.tastybento.bskyblock.database.mysql.adapters;
import java.io.IOException;
import org.bukkit.potion.PotionEffectType;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
public class PotionEffectTypeAdapter extends TypeAdapter<PotionEffectType> {
@Override
public void write(JsonWriter out, PotionEffectType value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.value(value.getName());
}
@Override
public PotionEffectType read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
return PotionEffectType.getByName(reader.nextString());
}
}

View File

@ -0,0 +1,39 @@
package us.tastybento.bskyblock.database.mysql.adapters;
import java.io.IOException;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
public class WorldAdapter extends TypeAdapter<World> {
private Plugin plugin;
public WorldAdapter(Plugin plugin) {
this.plugin = plugin;
}
@Override
public void write(JsonWriter out, World value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.value(value.getName());
}
@Override
public World read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
return plugin.getServer().getWorld(reader.nextString());
}
}

View File

@ -7,25 +7,19 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.gson.annotations.Expose;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.api.events.IslandBaseEvent;
import us.tastybento.bskyblock.api.events.island.IslandEvent;
import us.tastybento.bskyblock.api.events.island.IslandEvent.IslandLockEvent;
import us.tastybento.bskyblock.api.events.island.IslandEvent.IslandUnlockEvent;
import us.tastybento.bskyblock.api.events.island.IslandEvent.Reason;
import us.tastybento.bskyblock.api.flags.Flag;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.database.objects.adapters.Adapter;
import us.tastybento.bskyblock.database.objects.adapters.FlagSerializer;
import us.tastybento.bskyblock.managers.RanksManager;
@ -42,57 +36,71 @@ import us.tastybento.bskyblock.util.Util;
*/
public class Island implements DataObject {
private String uniqueId = "";
@Expose
private String uniqueId = UUID.randomUUID().toString();
//// Island ////
// The center of the island itself
@Expose
private Location center;
// Island range
@Expose
private int range;
// Coordinates of the island area
@Expose
private int minX;
@Expose
private int minZ;
// Coordinates of minimum protected area
@Expose
private int minProtectedX;
@Expose
private int minProtectedZ;
// Protection size
@Expose
private int protectionRange;
// World the island is in
// World the island started in. This may be different from the island location
@Expose
private World world;
// Display name
private String name;
@Expose
private String name = "";
// Time parameters
@Expose
private long createdDate;
@Expose
private long updatedDate;
//// Team ////
@Expose
private UUID owner;
@Expose
private Map<UUID, Integer> members = new HashMap<>();
//// State ////
@Expose
private boolean locked = false;
@Expose
private boolean spawn = false;
@Expose
private boolean purgeProtected = false;
//// Protection flags ////
@Adapter(FlagSerializer.class)
@Expose
private Map<Flag, Integer> flags = new HashMap<>();
@Expose
private int levelHandicap;
@Expose
private Location spawnPoint;
public Island() {}
@ -126,7 +134,6 @@ public class Island implements DataObject {
* @return true if successfully added
*/
public boolean addToBanList(UUID targetUUID) {
// TODO fire ban event
if (targetUUID != null) {
members.put(targetUUID, RanksManager.BANNED_RANK);
}
@ -206,7 +213,7 @@ public class Island implements DataObject {
*/
public ImmutableSet<UUID> getMemberSet(){
Builder<UUID> result = new ImmutableSet.Builder<>();
for (Entry<UUID, Integer> member: members.entrySet()) {
if (member.getValue() >= RanksManager.MEMBER_RANK) {
result.add(member.getKey());
@ -247,15 +254,7 @@ public class Island implements DataObject {
* @return the island display name or the owner's name if none is set
*/
public String getName() {
if (name != null) {
return name;
}
if (owner != null) {
OfflinePlayer player = Bukkit.getServer().getOfflinePlayer(owner);
name = player.getName();
return player.getName();
}
return "";
return name;
}
/**
@ -292,7 +291,6 @@ public class Island implements DataObject {
* @return rank integer
*/
public int getRank(User user) {
//Bukkit.getLogger().info("DEBUG: user UUID = " + user.getUniqueId());
return members.getOrDefault(user.getUniqueId(), RanksManager.VISITOR_RANK);
}
@ -353,10 +351,6 @@ public class Island implements DataObject {
@Override
public String getUniqueId() {
// Island's have UUID's that are randomly assigned if they do not exist
if (uniqueId.isEmpty()) {
uniqueId = UUID.randomUUID().toString();
}
return uniqueId;
}
@ -402,8 +396,7 @@ public class Island implements DataObject {
* @return true if in the island space
*/
public boolean inIslandSpace(int x, int z) {
//Bukkit.getLogger().info("DEBUG: center - " + center);
return x >= minX && x < minX + range*2 && z >= minZ && z < minZ + range*2;
return x >= minX && x < minX + range*2 && z >= minZ && z < minZ + range*2;
}
public boolean inIslandSpace(Location location) {
@ -439,7 +432,6 @@ public class Island implements DataObject {
* @return true if allowed, false if not
*/
public boolean isAllowed(User user, Flag flag) {
//Bukkit.getLogger().info("DEBUG: " + flag.getID() + " user score = " + getRank(user) + " flag req = "+ this.getFlagReq(flag));
return getRank(user) >= getFlag(flag);
}
@ -487,7 +479,6 @@ public class Island implements DataObject {
* @return true if successful, otherwise false.
*/
public boolean removeFromBanList(UUID targetUUID) {
// TODO fire unban event
members.remove(targetUUID);
return true;
}
@ -543,24 +534,11 @@ public class Island implements DataObject {
}
/**
* Locks/Unlocks the island. May be cancelled by
* {@link IslandLockEvent} or {@link IslandUnlockEvent}.
* Locks/Unlocks the island.
* @param locked - the lock state to set
*/
public void setLocked(boolean locked){
if(locked){
// Lock the island
IslandBaseEvent event = IslandEvent.builder().island(this).reason(Reason.LOCK).build();
if(!event.isCancelled()){
this.locked = locked;
}
} else {
// Unlock the island
IslandBaseEvent event = IslandEvent.builder().island(this).reason(Reason.UNLOCK).build();
if(!event.isCancelled()){
this.locked = locked;
}
}
this.locked = locked;
}
/**

View File

@ -10,6 +10,8 @@ import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import com.google.gson.annotations.Expose;
import us.tastybento.bskyblock.BSkyBlock;
/**
@ -18,13 +20,20 @@ import us.tastybento.bskyblock.BSkyBlock;
* @author tastybento
*/
public class Players implements DataObject {
private Map<Integer, Location> homeLocations;
@Expose
private Map<Integer, Location> homeLocations = new HashMap<>();
@Expose
private String uniqueId;
@Expose
private String playerName;
@Expose
private int resetsLeft;
@Expose
private String locale = "";
@Expose
private int deaths;
private Map<Location, Long> kickedList;
@Expose
private Map<Location, Long> kickedList = new HashMap<>();
/**
* This is required for database storage
@ -64,15 +73,6 @@ public class Players implements DataObject {
* @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);
}
@ -101,7 +101,6 @@ public class Players implements DataObject {
* @param homeLocations the homeLocations to set
*/
public void setHomeLocations(Map<Integer, Location> homeLocations) {
//Bukkit.getLogger().info("DEBUG: " + homeLocations.toString());
this.homeLocations = homeLocations;
}
@ -166,7 +165,7 @@ public class Players implements DataObject {
* Set the uuid for this player object
* @param uuid - UUID
*/
public void setPlayerUUID(final UUID uuid) {
public void setPlayerUUID(UUID uuid) {
uniqueId = uuid.toString();
}

View File

@ -11,8 +11,8 @@ import org.bukkit.event.player.PlayerQuitEvent;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.Constants;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.database.managers.PlayersManager;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.managers.PlayersManager;
public class JoinLeaveListener implements Listener {

View File

@ -18,8 +18,8 @@ import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.api.flags.Flag;
import us.tastybento.bskyblock.api.flags.Flag.Type;
import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.managers.IslandsManager;
/**
* Abstract class for flag listeners. Provides common code.

View File

@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.Listener;
import us.tastybento.bskyblock.BSkyBlock;

View File

@ -1,4 +1,4 @@
package us.tastybento.bskyblock.database.managers.island;
package us.tastybento.bskyblock.managers;
import java.util.Collection;
import java.util.HashSet;
@ -23,9 +23,10 @@ import org.bukkit.util.Vector;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.Constants;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.managers.island.IslandCache;
import us.tastybento.bskyblock.util.DeleteIslandChunks;
import us.tastybento.bskyblock.util.Util;
import us.tastybento.bskyblock.util.teleport.SafeTeleportBuilder;
@ -744,6 +745,7 @@ public class IslandsManager {
}
} catch (Exception e) {
plugin.getLogger().severe("Could not load islands to cache! " + e.getMessage());
e.printStackTrace();
}
if (DEBUG) {
plugin.getLogger().info("DEBUG: islands loaded");

View File

@ -1,4 +1,4 @@
package us.tastybento.bskyblock.database.managers;
package us.tastybento.bskyblock.managers;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
@ -19,6 +19,7 @@ import org.bukkit.entity.Player;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.Constants;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.database.objects.Players;
@ -250,7 +251,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 +262,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

@ -1,4 +1,4 @@
package us.tastybento.bskyblock.database.managers.island;
package us.tastybento.bskyblock.managers.island;
import java.util.Collection;
import java.util.Collections;
@ -296,7 +296,7 @@ public class IslandCache {
String result = plugin.getPlayers().getName(owner);
if (islandsByUUID.containsKey(owner)) {
Island island = islandsByUUID.get(owner);
if (!island.getName().isEmpty()) {
if (island.getName() != null && !island.getName().isEmpty()) {
result = island.getName();
}
}

View File

@ -1,4 +1,4 @@
package us.tastybento.bskyblock.database.managers.island;
package us.tastybento.bskyblock.managers.island;
import java.io.IOException;
import java.util.UUID;
@ -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

@ -56,12 +56,12 @@ import us.tastybento.bskyblock.api.events.IslandBaseEvent;
import us.tastybento.bskyblock.api.events.team.TeamEvent;
import us.tastybento.bskyblock.api.flags.Flag;
import us.tastybento.bskyblock.api.flags.FlagBuilder;
import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.generators.IslandWorld;
import us.tastybento.bskyblock.listeners.flags.AbstractFlagListener;
import us.tastybento.bskyblock.lists.Flags;
import us.tastybento.bskyblock.managers.FlagsManager;
import us.tastybento.bskyblock.managers.IslandsManager;
import us.tastybento.bskyblock.managers.RanksManager;
import us.tastybento.bskyblock.util.Util;

View File

@ -1,57 +1,81 @@
/**
*
*/
package us.tastybento.bskyblock.database.mysql;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
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.Mock;
import org.mockito.Mockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.Settings;
import us.tastybento.bskyblock.api.flags.Flag;
import us.tastybento.bskyblock.database.mysql.MySQLDatabaseConnecter;
import us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.database.objects.Players;
import us.tastybento.bskyblock.lists.Flags;
/**
* @author ben
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest( { BSkyBlock.class })
public class MySQLDatabaseHandlerTest {
private static MySQLDatabaseHandler<MySQLDatabaseHandlerTestDataObject> handler;
private static MySQLDatabaseHandlerTestDataObject instance;
private static MySQLDatabaseHandler<Island> handler;
private static Island instance;
private static String UNIQUE_ID = "xyz";
private static MySQLDatabaseConnecter dbConn;
private static World world;
@Mock
static BSkyBlock plugin = mock(BSkyBlock.class);
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUp() throws Exception {
public static void setUpBeforeClass() throws Exception {
Server server = mock(Server.class);
World world = mock(World.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);
BSkyBlock plugin = mock(BSkyBlock.class);
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
MySQLDatabaseConnecter dbConn = mock(MySQLDatabaseConnecter.class);
Whitebox.setInternalState(BSkyBlock.class, "instance", plugin);
Settings settings = mock(Settings.class);
when(plugin.getSettings()).thenReturn(settings);
when(settings.getDeathsMax()).thenReturn(10);
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);
@ -61,152 +85,74 @@ public class MySQLDatabaseHandlerTest {
ResultSet rs = mock(ResultSet.class);
when(ps.executeQuery()).thenReturn(rs);
when(statement.executeQuery(Mockito.anyString())).thenReturn(rs);
instance = new MySQLDatabaseHandlerTestDataObject();
instance = new Island();
instance.setUniqueId(UNIQUE_ID);
handler = new MySQLDatabaseHandler<>(plugin, MySQLDatabaseHandlerTestDataObject.class, dbConn);
handler = new MySQLDatabaseHandler<>(plugin, Island.class, dbConn);
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#getColumns(boolean)}.
*/
@Test
public void testGetColumns() {
// This should be a list of 20 ?'s which related to the 20
assertEquals("?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?", handler.getColumns(true));
assertEquals("`uniqueId`, `center`, `range`, `minX`, `minZ`, `minProtectedX`, `minProtectedZ`, " +
"`protectionRange`, `world`, `name`, `createdDate`, `updatedDate`, `owner`, `members`, `locked`, " +
"`spawn`, `purgeProtected`, `flags`, `levelHandicap`, `spawnPoint`",
handler.getColumns(false));
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#createSelectQuery()}.
*/
@Test
public void testCreateSelectQuery() {
assertEquals("SELECT `uniqueId`, `center`, `range`, `minX`, `minZ`, `minProtectedX`, " +
"`minProtectedZ`, `protectionRange`, `world`, `name`, `createdDate`, `updatedDate`, " +
"`owner`, `members`, `locked`, `spawn`, `purgeProtected`, `flags`, `levelHandicap`, " +
"`spawnPoint` FROM `us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandlerTestDataObject`",
handler.createSelectQuery());
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#createInsertQuery()}.
*/
@Test
public void testCreateInsertQuery() {
assertEquals("REPLACE INTO `us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandlerTestDataObject`(`uniqueId`, " +
"`center`, `range`, `minX`, `minZ`, `minProtectedX`, `minProtectedZ`, `protectionRange`, " +
"`world`, `name`, `createdDate`, `updatedDate`, `owner`, `members`, `locked`, `spawn`, " +
"`purgeProtected`, `flags`, `levelHandicap`, `spawnPoint`) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
handler.createInsertQuery());
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#createDeleteQuery()}.
*/
@Test
public void testCreateDeleteQuery() {
assertEquals("DELETE FROM [table_name] WHERE uniqueId = ?", handler.createDeleteQuery());
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#loadObjects()}.
*/
@Test
public void testLoadObjects() {
try {
java.util.List<MySQLDatabaseHandlerTestDataObject> result = handler.loadObjects();
System.out.println("Size of result " + result.size());
} catch (SecurityException | IllegalArgumentException | InstantiationException | IllegalAccessException
| InvocationTargetException | ClassNotFoundException | SQLException | IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#loadObject(java.lang.String)}.
*/
@Test
public void testLoadObject() {
try {
MySQLDatabaseHandlerTestDataObject obj = (MySQLDatabaseHandlerTestDataObject) handler.loadObject(UNIQUE_ID);
assertNull(obj);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| SecurityException | ClassNotFoundException | IntrospectionException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#saveObject(java.lang.Object)}.
*/
@Test
public void testSaveObject() {
try {
handler.saveObject(instance);
} catch (SecurityException | IllegalArgumentException | InstantiationException | IllegalAccessException
| InvocationTargetException | NoSuchMethodException | SQLException | IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
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);
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#deleteObject(java.lang.Object)}.
*/
@Test
public void testDeleteObject() {
try {
handler.deleteObject(instance);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
| SecurityException | IntrospectionException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
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);
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#objectExists(java.lang.String)}.
*/
@Test
public void testObjectExits() {
// This right now is not tested properly
assertFalse(handler.objectExists(UNIQUE_ID));
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#saveSettings(java.lang.Object)}.
*/
@Test
public void testSaveSettings() {
try {
handler.saveSettings(instance);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
| IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
MySQLDatabaseHandler<Players> h = new MySQLDatabaseHandler<>(plugin, Players.class, dbConn);
h.saveObject(players);
Island island = new Island();
island.setUniqueId(UNIQUE_ID);
island.setCenter(location);
Map<Flag, Integer> flags = new HashMap<>();
for (Flag fl : Flags.values()) {
flags.put(fl, 100);
}
}
/**
* Test method for {@link us.tastybento.bskyblock.database.mysql.MySQLDatabaseHandler#loadSettings(java.lang.String, java.lang.Object)}.
*/
@Test
public void testLoadSettings() {
try {
handler.loadSettings(UNIQUE_ID, instance);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| ClassNotFoundException | IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
island.setFlags(flags);
island.setLevelHandicap(10);
island.setLocked(true);
Map<UUID, Integer> members = new HashMap<>();
for (int i = 0; i < 100; i++) {
members.put(UUID.randomUUID(), i);
}
island.setMembers(members);
island.setMinProtectedX(-100);
island.setMinProtectedZ(-300);
island.setMinX(-121);
island.setMinZ(-23423);
island.setName("ytasdgfsdfg");
island.setOwner(UUID.randomUUID());
island.setProtectionRange(100);
island.setPurgeProtected(true);
island.setRange(100);
island.setSpawn(true);
island.setSpawnPoint(location);
island.setWorld(world);
MySQLDatabaseHandler<Island> ih = new MySQLDatabaseHandler<>(plugin, Island.class, dbConn);
ih.saveObject(island);
}
}

View File

@ -1,349 +0,0 @@
package us.tastybento.bskyblock.database.mysql;
import java.util.HashMap;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.World;
import us.tastybento.bskyblock.api.flags.Flag;
import us.tastybento.bskyblock.database.objects.DataObject;
import us.tastybento.bskyblock.database.objects.adapters.Adapter;
import us.tastybento.bskyblock.database.objects.adapters.FlagSerializer;
public class MySQLDatabaseHandlerTestDataObject implements DataObject {
private String uniqueId = "";
//// Island ////
// The center of the island itself
private Location center;
// Island range
private int range;
// Coordinates of the island area
private int minX;
private int minZ;
// Coordinates of minimum protected area
private int minProtectedX;
private int minProtectedZ;
// Protection size
private int protectionRange;
// World the island is in
private World world;
// Display name
private String name;
// Time parameters
private long createdDate;
private long updatedDate;
//// Team ////
private UUID owner;
private HashMap<UUID, Integer> members = new HashMap<>();
//// State ////
private boolean locked = false;
private boolean spawn = false;
private boolean purgeProtected = false;
//// Protection flags ////
@Adapter(FlagSerializer.class)
private HashMap<Flag, Integer> flags = new HashMap<>();
private int levelHandicap;
private Location spawnPoint;
public MySQLDatabaseHandlerTestDataObject() {}
/**
* @return the uniqueId
*/
public String getUniqueId() {
return uniqueId;
}
/**
* @param uniqueId - unique ID the uniqueId to set
*/
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
/**
* @return the center
*/
public Location getCenter() {
return center;
}
/**
* @param center the center to set
*/
public void setCenter(Location center) {
this.center = center;
}
/**
* @return the range
*/
public int getRange() {
return range;
}
/**
* @param range the range to set
*/
public void setRange(int range) {
this.range = range;
}
/**
* @return the minX
*/
public int getMinX() {
return minX;
}
/**
* @param minX the minX to set
*/
public void setMinX(int minX) {
this.minX = minX;
}
/**
* @return the minZ
*/
public int getMinZ() {
return minZ;
}
/**
* @param minZ the minZ to set
*/
public void setMinZ(int minZ) {
this.minZ = minZ;
}
/**
* @return the minProtectedX
*/
public int getMinProtectedX() {
return minProtectedX;
}
/**
* @param minProtectedX the minProtectedX to set
*/
public void setMinProtectedX(int minProtectedX) {
this.minProtectedX = minProtectedX;
}
/**
* @return the minProtectedZ
*/
public int getMinProtectedZ() {
return minProtectedZ;
}
/**
* @param minProtectedZ the minProtectedZ to set
*/
public void setMinProtectedZ(int minProtectedZ) {
this.minProtectedZ = minProtectedZ;
}
/**
* @return the protectionRange
*/
public int getProtectionRange() {
return protectionRange;
}
/**
* @param protectionRange the protectionRange to set
*/
public void setProtectionRange(int protectionRange) {
this.protectionRange = protectionRange;
}
/**
* @return the world
*/
public World getWorld() {
return world;
}
/**
* @param world the world to set
*/
public void setWorld(World world) {
this.world = world;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the createdDate
*/
public long getCreatedDate() {
return createdDate;
}
/**
* @param createdDate the createdDate to set
*/
public void setCreatedDate(long createdDate) {
this.createdDate = createdDate;
}
/**
* @return the updatedDate
*/
public long getUpdatedDate() {
return updatedDate;
}
/**
* @param updatedDate the updatedDate to set
*/
public void setUpdatedDate(long updatedDate) {
this.updatedDate = updatedDate;
}
/**
* @return the owner
*/
public UUID getOwner() {
return owner;
}
/**
* @param owner - the island owner the owner to set
*/
public void setOwner(UUID owner) {
this.owner = owner;
}
/**
* @return the members
*/
public HashMap<UUID, Integer> getMembers() {
return members;
}
/**
* @param members the members to set
*/
public void setMembers(HashMap<UUID, Integer> members) {
this.members = members;
}
/**
* @return the locked
*/
public boolean isLocked() {
return locked;
}
/**
* @param locked the locked to set
*/
public void setLocked(boolean locked) {
this.locked = locked;
}
/**
* @return the spawn
*/
public boolean isSpawn() {
return spawn;
}
/**
* @param spawn the spawn to set
*/
public void setSpawn(boolean spawn) {
this.spawn = spawn;
}
/**
* @return the purgeProtected
*/
public boolean isPurgeProtected() {
return purgeProtected;
}
/**
* @param purgeProtected the purgeProtected to set
*/
public void setPurgeProtected(boolean purgeProtected) {
this.purgeProtected = purgeProtected;
}
/**
* @return the flags
*/
public HashMap<Flag, Integer> getFlags() {
return flags;
}
/**
* @param flags the flags to set
*/
public void setFlags(HashMap<Flag, Integer> flags) {
this.flags = flags;
}
/**
* @return the levelHandicap
*/
public int getLevelHandicap() {
return levelHandicap;
}
/**
* @param levelHandicap the levelHandicap to set
*/
public void setLevelHandicap(int levelHandicap) {
this.levelHandicap = levelHandicap;
}
/**
* @return the spawnPoint
*/
public Location getSpawnPoint() {
return spawnPoint;
}
/**
* @param spawnPoint the spawnPoint to set
*/
public void setSpawnPoint(Location spawnPoint) {
this.spawnPoint = spawnPoint;
}
}

View File

@ -42,11 +42,11 @@ import org.powermock.modules.junit4.PowerMockRunner;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.Settings;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.generators.IslandWorld;
import us.tastybento.bskyblock.lists.Flags;
import us.tastybento.bskyblock.managers.FlagsManager;
import us.tastybento.bskyblock.managers.IslandsManager;
import us.tastybento.bskyblock.managers.LocalesManager;
@RunWith(PowerMockRunner.class)

View File

@ -33,11 +33,11 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.generators.IslandWorld;
import us.tastybento.bskyblock.lists.Flags;
import us.tastybento.bskyblock.managers.FlagsManager;
import us.tastybento.bskyblock.managers.IslandsManager;
@RunWith(PowerMockRunner.class)
@PrepareForTest( { Flags.class })