Database done, compiles, runs without bugs so far.

This implements flat file database. MySQL is still to do. IslandManager
now uses this. PlayerManager is still to convert.
This commit is contained in:
tastybento 2017-05-24 23:09:09 -07:00
parent 20d74e19c9
commit fb7768e964
21 changed files with 550 additions and 742 deletions

View File

@ -37,7 +37,7 @@ public class BSkyBlock extends JavaPlugin{
@Override
public void onEnable(){
plugin = this;
new RunTest(this);
//new RunTest(this);
playersManager = new PlayersManager(this);
islandsManager = new IslandsManager(this);
@ -66,7 +66,7 @@ public class BSkyBlock extends JavaPlugin{
}
// Save islands & players data asynchronously every X minutes
plugin.getServer().getScheduler().runTaskTimer(this, new Runnable() {
getServer().getScheduler().runTaskTimer(this, new Runnable() {
@Override
public void run() {

View File

@ -1,14 +1,29 @@
package us.tastybento.bskyblock.database;
import java.beans.IntrospectionException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.objects.Island;
/**
* An abstract class that handles insert/select-operations into/from a database
*
* @param <T>
*/
/**
* @author tastybento
*
* @param <T>
*/
/**
* @author tastybento
*
* @param <T>
*/
public abstract class AbstractDatabaseHandler<T> {
/**
@ -23,11 +38,14 @@ public abstract class AbstractDatabaseHandler<T> {
*/
protected DatabaseConnecter databaseConnecter;
/** The SQL-select-query */
protected final String query;
/** The SQL-select- and insert query */
protected final String selectQuery;
protected final String insertQuery;
protected BSkyBlock plugin;
/**
* Constructor
*
@ -44,21 +62,23 @@ public abstract class AbstractDatabaseHandler<T> {
this.plugin = plugin;
this.databaseConnecter = databaseConnecter;
this.type = type;
this.query = createQuery();
this.selectQuery = createSelectQuery();
this.insertQuery = createInsertQuery();
}
/**
* Create the SQL-String to insert into / select from the database
*
* Not used in the flat file database
* @return the SQL-String
*/
protected abstract String createQuery();
protected abstract String createSelectQuery();
protected abstract String createInsertQuery();
/**
*
* 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
@ -84,4 +104,44 @@ public abstract class AbstractDatabaseHandler<T> {
return sb.toString();
}
/**
* Loads all the records in this table and returns a list of them
* @return list of <T>
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws IntrospectionException
* @throws SecurityException
* @throws SQLException
*/
protected abstract List<T> selectObjects() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException, SQLException, SecurityException;
/**
* Creates a <T> filled with values from the corresponding
* database file
* @param uniqueId
* @return <T>
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InstantiationException
*/
protected abstract T selectObject(String uniqueId) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException;
/**
* Inserts T into the corresponding database-table
*
* @param instance that should be inserted into the database
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws IntrospectionException
* @throws InstantiationException
* @throws SecurityException
* @throws SQLException
*/
protected abstract void insertObject(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException, SQLException, SecurityException, InstantiationException;
}

View File

@ -1,15 +1,9 @@
package us.tastybento.bskyblock.database;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.config.Settings;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase;
import us.tastybento.bskyblock.database.mysql.MySQLDatabase;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.database.objects.Players;
import us.tastybento.bskyblock.database.sqlite.SQLiteDatabase;
public abstract class BSBDatabase {
@ -21,26 +15,6 @@ public abstract class BSBDatabase {
return DatabaseType.FLATFILE.database;
}
public abstract boolean connect(BSkyBlock plugin);
public abstract Players loadPlayerData(UUID uuid);
public abstract void savePlayerData(Players player);
/**
* Loads an island
* @param location
* @return
*/
public abstract Island loadIslandData(String location);
/**
* Saves an island to the database
* @param island
* @return
*/
public abstract boolean saveIslandData(Island island);
public abstract HashMap<UUID, List<String>> loadOfflineHistoryMessages();
public abstract void saveOfflineHistoryMessages(HashMap<UUID, List<String>> messages);
public enum DatabaseType{
FLATFILE(new FlatFileDatabase()),
MYSQL(new MySQLDatabase()),
@ -54,25 +28,14 @@ public abstract class BSBDatabase {
}
/**
* Checks in database whether the player is known by the plugin or not
* @param uniqueID
* @return true or false
* Gets a handler for this class type with this database connection
* @param plugin
* @param type
* @param databaseConnecter
* @return selector object
*/
public abstract boolean isPlayerKnown(UUID uniqueID);
public abstract AbstractDatabaseHandler<?> getHandler(BSkyBlock plugin, Class<?> type);
/**
* Gets the UUID for player with name. If adminCheck is true, the search will be more extensive
* @param name
* @param adminCheck
* @return UUID of player with name, or null if it cannot be found
*/
public abstract UUID getUUID(String name, boolean adminCheck);
/**
* Associates this name with the UUID
* @param name
* @param uuid
*/
public abstract void savePlayerName(String name, UUID uuid);
}

View File

@ -2,7 +2,6 @@ package us.tastybento.bskyblock.database;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.UUID;
import org.bukkit.configuration.file.YamlConfiguration;
@ -28,22 +27,16 @@ public interface DatabaseConnecter {
*/
public String getConnectionUrl();
/**
* @param simpleName
* @return
*/
public YamlConfiguration loadYamlFile(String simpleName);
/**
* @param config
* @param simpleName
*/
public void saveYamlFile(YamlConfiguration config, String simpleName);
/**
* Looks through the database (or files) and returns a known unique key
* @param tableName
* @return a unique key for this record
*/
public UUID getUniqueId();
public String getUniqueId(String tableName);
public YamlConfiguration loadYamlFile(String string, String key);
public void saveYamlFile(YamlConfiguration yamlFile, String tableName,
String fileName);
}

View File

@ -27,18 +27,30 @@ public class IslandsManager {
// Metrics data
private int metrics_createdcount = 0;
private AbstractDatabaseHandler<Island> handler;
public IslandsManager(BSkyBlock plugin){
this.plugin = plugin;
database = BSBDatabase.getDatabase();
database.connect(plugin);
handler = (AbstractDatabaseHandler<Island>) database.getHandler(plugin, Island.class);
islands = new HashMap<Location, Island>();
islandsByUUID = new HashMap<UUID, Island>();
spawn = null;
//load();
}
public void load(){
//TODO
try {
for (Object island : handler.selectObjects()) {
if (island instanceof Island) {
islands.put(((Island)island).getCenter(), (Island)island);
islandsByUUID.put(((Island)island).getOwner(), (Island)island);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void save(boolean async){
@ -47,14 +59,24 @@ public class IslandsManager {
@Override
public void run() {
for(Entry<Location, Island> entry : islands.entrySet()){
database.saveIslandData(entry.getValue());
for(Island island : islands.values()){
try {
handler.insertObject(island);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
} else {
for(Entry<Location, Island> entry : islands.entrySet()){
database.saveIslandData(entry.getValue());
for(Island island : islands.values()){
try {
handler.insertObject(island);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

View File

@ -29,7 +29,7 @@ public class OfflineHistoryMessages {
}
public void load(){
messages = database.loadOfflineHistoryMessages();
//messages = database.loadOfflineHistoryMessages();
}
public void save(boolean async){
@ -38,11 +38,11 @@ public class OfflineHistoryMessages {
@Override
public void run() {
database.saveOfflineHistoryMessages(messages);
//database.saveOfflineHistoryMessages(messages);
}
});
} else {
database.saveOfflineHistoryMessages(messages);
//database.saveOfflineHistoryMessages(messages);
}
}

View File

@ -38,21 +38,7 @@ public class PlayersManager{
}
public void save(boolean async){
if(async){
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
for(Entry<UUID, Players> entry : playerCache.entrySet()){
database.savePlayerData(entry.getValue());
}
}
});
} else {
for(Entry<UUID, Players> entry : playerCache.entrySet()){
database.savePlayerData(entry.getValue());
}
}
// TODO
}
public void shutdown(){
@ -89,7 +75,7 @@ public class PlayersManager{
*/
public void removeOnlinePlayer(final UUID player) {
if (playerCache.containsKey(player)) {
database.savePlayerData(playerCache.get(player));
//database.savePlayerData(playerCache.get(player));
playerCache.remove(player);
// plugin.getLogger().info("Removing player from cache: " + player);
}
@ -100,7 +86,7 @@ public class PlayersManager{
*/
public void removeAllPlayers() {
for (UUID pl : playerCache.keySet()) {
database.savePlayerData(playerCache.get(pl));
//database.savePlayerData(playerCache.get(pl));
}
playerCache.clear();
}
@ -124,7 +110,9 @@ public class PlayersManager{
return true;
} else {
// Get from the database - do not add to cache yet
return database.isPlayerKnown(uniqueID) ? true: false;
//return database.isPlayerKnown(uniqueID) ? true: false;
// TODO
return false;
}
}
@ -263,7 +251,8 @@ public class PlayersManager{
@SuppressWarnings("deprecation")
public UUID getUUID(String string, boolean adminCheck) {
// Look in the database if it ready
return database.getUUID(string, adminCheck);
//return database.getUUID(string, adminCheck);
return null;
}
/**
@ -274,7 +263,7 @@ public class PlayersManager{
public void setPlayerName(UUID uniqueId, String name) {
addPlayer(uniqueId);
playerCache.get(uniqueId).setPlayerN(name);
database.savePlayerName(name, uniqueId);
//database.savePlayerName(name, uniqueId);
}
/**

View File

@ -6,8 +6,6 @@ import org.bukkit.Location;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabaseConnecter;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabaseInserter;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabaseSelecter;
import us.tastybento.bskyblock.database.objects.Island;
public class RunTest {
@ -38,15 +36,14 @@ public class RunTest {
items.add(new ItemStack(Material.FEATHER,5));
test.setInventory(items);
*/
FlatFileDatabaseInserter<Island> inserter = new FlatFileDatabaseInserter<Island>(plugin, Island.class, connecter);
BSBDatabase database = BSBDatabase.getDatabase();
AbstractDatabaseHandler<Island> handler = (AbstractDatabaseHandler<Island>) database.getHandler(plugin, Island.class);
inserter.insertObject(test);
handler.insertObject(test);
plugin.getLogger().info("DEBUG: ALL WRITTEN! Now reading...");
FlatFileDatabaseSelecter<Island> selecter = new FlatFileDatabaseSelecter<Island>(plugin, Island.class, connecter);
test = selecter.selectObject(test.getUuid().toString());
test = handler.selectObject(test.getUniqueId());
plugin.getLogger().info("DEBUG: name = " + test.getName());
plugin.getLogger().info("DEBUG: owner = " + test.getOwner());

View File

@ -1,108 +1,16 @@
package us.tastybento.bskyblock.database.flatfile;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.DatabaseConnecter;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.database.objects.Players;
public class FlatFileDatabase extends BSBDatabase{
private BSkyBlock plugin;
DatabaseConnecter connecter;
@Override
public UUID getUUID(String name, boolean adminCheck) {
/*
if (plugin.getTinyDB() != null && plugin.getTinyDB().isDbReady()) {
UUID result = plugin.getTinyDB().getPlayerUUID(string);
if (result != null) {
return result;
}
}
// This goes after the database because it is possible for islands that have a duplicate name to be in
// the cache. For example, Bill had an island but left. Bill changes his name to Bob. Then Alice changes
// her name to Bill and logs into the game. There are now two islands with owner names called "Bill"
// The name database will ensure the names are updated.
for (UUID id : playerCache.keySet()) {
String name = playerCache.get(id).getPlayerName();
//plugin.getLogger().info("DEBUG: Testing name " + name);
if (name != null && name.equalsIgnoreCase(string)) {
//plugin.getLogger().info("DEBUG: found it! " + id);
return id;
}
}
*/
// Try the server
if (adminCheck) {
return Bukkit.getServer().getOfflinePlayer(name).getUniqueId();
}
return null;
}
@Override
public Players loadPlayerData(UUID uuid) {
// TODO Auto-generated method stub
return null;
}
@Override
public void savePlayerData(Players player) {
// TODO Auto-generated method stub
public AbstractDatabaseHandler<?> getHandler(BSkyBlock plugin, Class<?> type) {
return new FlatFileDatabaseHandler<Island>(plugin, Island.class, new FlatFileDatabaseConnecter(plugin, null));
}
@Override
public Island loadIslandData(String location) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean saveIslandData(Island island) {
FlatFileDatabaseInserter<Island> inserter = new FlatFileDatabaseInserter<Island>(plugin, Island.class, connecter);
try {
inserter.insertObject(island);
} catch (Exception e) {
return false;
}
return true;
}
@Override
public HashMap<UUID, List<String>> loadOfflineHistoryMessages() {
// TODO Auto-generated method stub
return null;
}
@Override
public void saveOfflineHistoryMessages(HashMap<UUID, List<String>> messages) {
// TODO Auto-generated method stub
}
@Override
public boolean isPlayerKnown(UUID uniqueID) {
// TODO Auto-generated method stub
return false;
}
@Override
public void savePlayerName(String name, UUID uuid) {
// TODO Auto-generated method stub
}
@Override
public boolean connect(BSkyBlock plugin) {
this.plugin = plugin;
this.connecter = new FlatFileDatabaseConnecter(plugin, null);
return false;
}
}

View File

@ -14,13 +14,14 @@ import us.tastybento.bskyblock.database.DatabaseConnectionSettingsImpl;
public class FlatFileDatabaseConnecter implements DatabaseConnecter {
private static final int MAX_LOOPS = 100;
private static final String DATABASE_FOLDER_NAME = "database";
private BSkyBlock plugin;
private File dataFolder;
public FlatFileDatabaseConnecter(BSkyBlock plugin, DatabaseConnectionSettingsImpl databaseConnectionSettingsImpl) {
this.plugin = plugin;
dataFolder = new File(plugin.getDataFolder(), "database");
dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
}
@Override
@ -41,9 +42,11 @@ public class FlatFileDatabaseConnecter implements DatabaseConnecter {
* @param fileName
* @return
*/
@Override
public YamlConfiguration loadYamlFile(String fileName) {
File yamlFile = new File(dataFolder, fileName + ".yml");
public YamlConfiguration loadYamlFile(String tableName, String fileName) {
if (!fileName.endsWith(".yml")) {
fileName = fileName + ".yml";
}
File yamlFile = new File(dataFolder, tableName + File.separator + fileName);
YamlConfiguration config = null;
if (yamlFile.exists()) {
@ -80,9 +83,15 @@ public class FlatFileDatabaseConnecter implements DatabaseConnecter {
* @param fileName
*/
@Override
public void saveYamlFile(YamlConfiguration yamlFile, String fileName) {
File file = new File(dataFolder, fileName + ".yml");
public void saveYamlFile(YamlConfiguration yamlFile, String tableName, String fileName) {
if (!fileName.endsWith(".yml")) {
fileName = fileName + ".yml";
}
File tableFolder = new File(dataFolder, tableName);
File file = new File(tableFolder, fileName);
if (!tableFolder.exists()) {
tableFolder.mkdirs();
}
try {
yamlFile.save(file);
} catch (Exception e) {
@ -91,15 +100,15 @@ public class FlatFileDatabaseConnecter implements DatabaseConnecter {
}
@Override
public UUID getUniqueId() {
public String getUniqueId(String tableName) {
UUID uuid = UUID.randomUUID();
File file = new File(dataFolder, uuid.toString() + ".yml");
File file = new File(dataFolder, tableName + File.separator + uuid.toString() + ".yml");
int limit = 0;
while (file.exists() && limit++ < MAX_LOOPS) {
uuid = UUID.randomUUID();
file = new File(dataFolder, uuid.toString() + ".yml");
file = new File(dataFolder, tableName + File.separator + uuid.toString() + ".yml");
}
return uuid;
return uuid.toString();
}
}

View File

@ -0,0 +1,243 @@
package us.tastybento.bskyblock.database.flatfile;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.configuration.file.YamlConfiguration;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.DatabaseConnecter;
/**
*
* Class that creates a list of <T>s filled with values from the corresponding
* database-table.
*
* @author tastybento
*
* @param <T>
*/
public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
private static final String DATABASE_FOLDER_NAME = "database";
public FlatFileDatabaseHandler(BSkyBlock plugin, Class<T> type,
DatabaseConnecter databaseConnecter) {
super(plugin, type, databaseConnecter);
}
@Override
protected String createSelectQuery() {
// not used
return "";
}
@Override
protected String createInsertQuery() {
// not used
return "";
}
/**
* Creates a <T> filled with values from the corresponding
* database file
*
* @return <T> filled with values from the corresponding database file
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@Override
public T selectObject(String key) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
YamlConfiguration config = databaseConnecter.loadYamlFile(type.getSimpleName(), key);
return createObject(config);
}
/**
* Loads all the records in this table and returns a list of them
* @return list of <T>
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws IntrospectionException
*/
@Override
public List<T> selectObjects() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
List<T> list = new ArrayList<T>();
FilenameFilter ymlFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
String lowercaseName = name.toLowerCase();
if (lowercaseName.endsWith(".yml")) {
return true;
} else {
return false;
}
}
};
File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
File tableFolder = new File(dataFolder, type.getSimpleName());
if (!tableFolder.exists()) {
// Nothing there...
tableFolder.mkdirs();
}
for (File file: tableFolder.listFiles(ymlFilter)) {
YamlConfiguration config = databaseConnecter.loadYamlFile(type.getSimpleName(), file.getName());
list.add(createObject(config));
}
return list;
}
/**
*
* Creates a list of <T>s filled with values from the provided ResultSet
*
* @param config - YAML config file
*
* @return <T> filled with values
*
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IntrospectionException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
private T createObject(YamlConfiguration config) throws InstantiationException, IllegalAccessException,
IntrospectionException, IllegalArgumentException, InvocationTargetException
{
T instance = type.newInstance();
for (Field field : type.getDeclaredFields()) {
/* We assume the table-column-names exactly match the variable-names of T */
// TODO: depending on the data type, it'll need deserializing
try {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type);
Method method = propertyDescriptor.getWriteMethod();
plugin.getLogger().info("DEBUG: " + field.getName() + ": " + propertyDescriptor.getPropertyType().getTypeName());
if (propertyDescriptor.getPropertyType().equals(HashMap.class)) {
plugin.getLogger().info("DEBUG: is HashMap");
// TODO: this may not work with all keys. Further serialization may be required.
HashMap<Object,Object> value = new HashMap<Object, Object>();
for (String key : config.getConfigurationSection(field.getName()).getKeys(false)) {
value.put(key, config.get(field.getName() + "." + key));
}
method.invoke(instance, value);
} else if (propertyDescriptor.getPropertyType().equals(Set.class)) {
plugin.getLogger().info("DEBUG: is Set " + propertyDescriptor.getReadMethod().getGenericReturnType().getTypeName());
// TODO: this may not work with all keys. Further serialization may be required.
Set<Object> value = new HashSet((List<Object>) config.getList(field.getName()));
method.invoke(instance, value);
} else if (propertyDescriptor.getPropertyType().equals(UUID.class)) {
plugin.getLogger().info("DEBUG: is UUID");
String uuid = (String)config.get(field.getName());
if (uuid == null || uuid.equals("null")) {
method.invoke(instance, (Object)null);
} else {
Object value = UUID.fromString(uuid);
method.invoke(instance, value);
}
} else {
Object value = config.get(field.getName());
method.invoke(instance, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
/**
* Inserts T into the corresponding database-table
*
* @param instance that should be inserted into the database
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws IntrospectionException
*/
@SuppressWarnings("unchecked")
@Override
public void insertObject(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
// This is the Yaml Configuration that will be used and saved at the end
YamlConfiguration config = new YamlConfiguration();
// The file name of the Yaml file.
String filename = "";
// Run through all the fields in the class that is being stored. EVERY field must have a get and set method
for (Field field : type.getDeclaredFields()) {
// Get the property descriptor for this field
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type);
// Get the read method, i.e., getXXXX();
Method method = propertyDescriptor.getReadMethod();
// Invoke the read method to get the value. We have no idea what type of value it is.
Object value = method.invoke(instance);
plugin.getLogger().info("DEBUG: writing " + field.getName());
plugin.getLogger().info("DEBUG: property desc = " + propertyDescriptor.getPropertyType().getTypeName());
// Depending on the vale type, it'll need serializing differenty
// Check if this field is the mandatory UniqueId field. This is used to identify this instantiation of the class
if (method.getName().equals("getUniqueId")) {
// If the object does not have a unique name assigned to it already, one is created at random
plugin.getLogger().info("DEBUG: uniqueId = " + value);
String id = (String)value;
if (id.isEmpty()) {
id = databaseConnecter.getUniqueId(type.getSimpleName());
// Set it in the class so that it will be used next time
propertyDescriptor.getWriteMethod().invoke(instance, id);
}
// Save the name for when the file is saved
filename = id;
}
// UUID's need special serialization
if (propertyDescriptor.getPropertyType().equals(UUID.class)) {
plugin.getLogger().info("DEBUG: writing UUID for " + field.getName());
if (value != null) {
config.set(field.getName(), ((UUID)value).toString());
} else {
// UUID's can be null, so they need to be saved as the string "null"
config.set(field.getName(), "null");
}
} else if (propertyDescriptor.getPropertyType().equals(Set.class)) {
// Sets need to be serialized as string lists
plugin.getLogger().info("DEBUG: Set for " + field.getName());
List<Object> list = new ArrayList<Object>();
for (Object object : (Set<Object>)value) {
if (object instanceof UUID) {
list.add(((UUID)object).toString());
}
}
// Save the list in the config file
config.set(field.getName(), list);
} else {
// For all other data that doesn't need special serialization
config.set(field.getName(), value);
}
}
if (filename.isEmpty()) {
throw new IllegalArgumentException("No UUID in class");
}
// Save the file in the right folder
databaseConnecter.saveYamlFile(config, type.getSimpleName(), filename);
}
}

View File

@ -1,150 +0,0 @@
package us.tastybento.bskyblock.database.flatfile;
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.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.DatabaseConnecter;
/**
*
* Class that inserts a list of <T>s into the corresponding YAML file.
*
* @author tastybento
*
* @param <T>
*/
public class FlatFileDatabaseInserter<T> extends AbstractDatabaseHandler<T> {
public FlatFileDatabaseInserter(BSkyBlock plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
super(plugin, type, databaseConnecter);
}
@Override
protected String createQuery() {
// Not used for flat file
return "";
}
/**
* Inserts T into the corresponding database-table
*
* @param instance that should be inserted into the database
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
* @throws IntrospectionException
*/
public void insertObject(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
YamlConfiguration config = new YamlConfiguration();
String filename = "";
for (Field field : type.getDeclaredFields()) {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type);
Method method = propertyDescriptor.getReadMethod();
Object value = method.invoke(instance);
plugin.getLogger().info("DEBUG: writing " + field.getName());
plugin.getLogger().info("DEBUG: property desc = " + propertyDescriptor.getPropertyType().getTypeName());
// TODO: depending on the type, it'll need serializing
if (propertyDescriptor.getPropertyType().equals(UUID.class)) {
plugin.getLogger().info("DEBUG: writing UUID for " + field.getName());
// Check if this is the UUID
if (method.getName().equals("getUuid")) {
if (value == null) {
value = databaseConnecter.getUniqueId();
// Set it in the class
propertyDescriptor.getWriteMethod().invoke(instance, value);
}
filename = value.toString();
}
if (value != null) {
config.set(field.getName(), ((UUID)value).toString());
} else {
config.set(field.getName(), "null");
}
} else if (propertyDescriptor.getPropertyType().equals(Set.class)) {
plugin.getLogger().info("DEBUG: Hashset for " + field.getName());
List<Object> list = new ArrayList<Object>();
for (Object object : (Set<Object>)value) {
if (object instanceof UUID) {
list.add(((UUID)object).toString());
}
}
config.set(field.getName(), list);
} else {
config.set(field.getName(), value);
}
}
if (filename.isEmpty()) {
throw new IllegalArgumentException("No UUID in class");
}
databaseConnecter.saveYamlFile(config, filename);
}
/**
* Saves a Map at the specified ConfigurationSection.
* @param section the ConfigurationSection
* @param map the Map, note that the String parameter in the map refers to the keys the objects are saved in
* @throws IllegalArgumentException when either the ConfigurationSection or the Map is null
*/
@SuppressWarnings("unchecked")
public static void saveMap(final ConfigurationSection section, final Map<String, Object> map) throws IllegalArgumentException {
if (section == null || map == null)
throw new IllegalArgumentException("Both the configuration section and the map to save must not be null");
final Iterator<Entry<String, Object>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
final Entry<String, Object> entry = iter.next();
final Object value = entry.getValue();
final String key = entry.getKey();
if (value instanceof Map) {
saveMap(section.createSection(key), (Map<String, Object>) value);
} else if (value instanceof Collection) {
saveCollection(section, (Collection<Object>) value);
} else {
section.set(key, value);
}
}
}
/**
* Saves a Collection at the specified ConfigurationSection.
* @param section the ConfigurationSection
* @param collection the Collection
* @throws IllegalArgumentException when either the ConfigurationSection or the Collection is null
*/
public static void saveCollection(final ConfigurationSection section, final Collection<Object> collection) throws IllegalArgumentException {
if (section == null || collection == null)
throw new IllegalArgumentException("Both the configuration section and the iterable object to save must not be null");
final Iterator<Object> iter = collection.iterator();
final String currentSectionPath = section.getCurrentPath();
while (iter.hasNext()) {
final Object value = iter.next();
section.set(currentSectionPath, value);
}
}
}

View File

@ -1,125 +0,0 @@
package us.tastybento.bskyblock.database.flatfile;
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.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.configuration.file.YamlConfiguration;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.DatabaseConnecter;
/**
*
* Class that creates a list of <T>s filled with values from the corresponding
* database-table.
*
* @author tastybento
*
* @param <T>
*/
public class FlatFileDatabaseSelecter<T> extends AbstractDatabaseHandler<T> {
public FlatFileDatabaseSelecter(BSkyBlock plugin, Class<T> type,
DatabaseConnecter databaseConnecter) {
super(plugin, type, databaseConnecter);
}
@Override
protected String createQuery() {
return "";
}
/**
* Creates a <T> filled with values from the corresponding
* database file
*
* @return <T> filled with values from the corresponding database file
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public T selectObject(String key) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
YamlConfiguration config = databaseConnecter.loadYamlFile(key);
return createObject(config);
}
/**
*
* Creates a list of <T>s filled with values from the provided ResultSet
*
* @param config - YAML config file
*
* @return <T> filled with values
*
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IntrospectionException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
private T createObject(YamlConfiguration config) throws InstantiationException, IllegalAccessException,
IntrospectionException, IllegalArgumentException, InvocationTargetException
{
T instance = type.newInstance();
for (Field field : type.getDeclaredFields()) {
/* We assume the table-column-names exactly match the variable-names of T */
// TODO: depending on the data type, it'll need deserializing
try {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
field.getName(), type);
Method method = propertyDescriptor.getWriteMethod();
plugin.getLogger().info("DEBUG: " + field.getName() + ": " + propertyDescriptor.getPropertyType().getTypeName());
if (propertyDescriptor.getPropertyType().equals(HashMap.class)) {
plugin.getLogger().info("DEBUG: is HashMap");
// TODO: this may not work with all keys. Further serialization may be required.
HashMap<Object,Object> value = new HashMap<Object, Object>();
for (String key : config.getConfigurationSection(field.getName()).getKeys(false)) {
value.put(key, config.get(field.getName() + "." + key));
}
method.invoke(instance, value);
} else if (propertyDescriptor.getPropertyType().equals(Set.class)) {
plugin.getLogger().info("DEBUG: is Set " + propertyDescriptor.getReadMethod().getGenericReturnType().getTypeName());
// TODO: this may not work with all keys. Further serialization may be required.
Set<Object> value = new HashSet((List<Object>) config.getList(field.getName()));
method.invoke(instance, value);
} else if (propertyDescriptor.getPropertyType().equals(UUID.class)) {
plugin.getLogger().info("DEBUG: is UUID");
String uuid = (String)config.get(field.getName());
if (uuid == null || uuid.equals("null")) {
method.invoke(instance, (Object)null);
} else {
Object value = UUID.fromString(uuid);
method.invoke(instance, value);
}
} else {
Object value = config.get(field.getName());
method.invoke(instance, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
}

View File

@ -1,74 +1,18 @@
package us.tastybento.bskyblock.database.mysql;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabaseConnecter;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.database.objects.Players;
public class MySQLDatabase extends BSBDatabase{
@Override
public Players loadPlayerData(UUID uuid) {
// TODO Auto-generated method stub
return null;
}
@Override
public void savePlayerData(Players player) {
// TODO Auto-generated method stub
public AbstractDatabaseHandler<?> getHandler(BSkyBlock plugin, Class<?> type) {
return new MySQLDatabaseHandler<Island>(plugin, Island.class, new FlatFileDatabaseConnecter(plugin, null));
}
@Override
public Island loadIslandData(String location) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean saveIslandData(Island island) {
// TODO Auto-generated method stub
return false;
}
@Override
public HashMap<UUID, List<String>> loadOfflineHistoryMessages() {
// TODO Auto-generated method stub
return null;
}
@Override
public void saveOfflineHistoryMessages(HashMap<UUID, List<String>> messages) {
// TODO Auto-generated method stub
}
@Override
public boolean isPlayerKnown(UUID uniqueID) {
// TODO Auto-generated method stub
return false;
}
@Override
public UUID getUUID(String name, boolean adminCheck) {
// TODO Auto-generated method stub
return null;
}
@Override
public void savePlayerName(String name, UUID uuid) {
// TODO Auto-generated method stub
}
@Override
public boolean connect(BSkyBlock plugin) {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -6,6 +6,7 @@ import java.lang.reflect.Field;
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;
@ -16,25 +17,23 @@ import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.DatabaseConnecter;
/**
*
* Class that creates a list of <T>s filled with values from the corresponding
* database-table.
* Class that inserts a <T> into the corresponding database-table.
*
* @author Tino for http://www.java-blog.com
* @author tastybento
*
* @param <T>
*/
public class MySQLDatabaseSelecter<T> extends AbstractDatabaseHandler<T> {
public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
public MySQLDatabaseSelecter(BSkyBlock plugin, Class<T> type,
public MySQLDatabaseHandler(BSkyBlock plugin, Class<T> type,
DatabaseConnecter databaseConnecter) {
super(plugin, type, databaseConnecter);
}
@Override
protected String createQuery() {
protected String createSelectQuery() {
StringBuilder sb = new StringBuilder();
@ -48,6 +47,72 @@ public class MySQLDatabaseSelecter<T> extends AbstractDatabaseHandler<T> {
return sb.toString();
}
@Override
protected String createInsertQuery() {
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO ");
sb.append(type.getSimpleName());
sb.append("(");
sb.append(super.getColumns(false));
sb.append(")");
sb.append(" VALUES (");
sb.append(super.getColumns(true));
sb.append(")");
return sb.toString();
}
/**
* Inserts a <T> into the corresponding database-table
*
* @param instance <T> that should be inserted into the corresponding database-table
* @throws SQLException
* @throws SecurityException
* @throws IllegalArgumentException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IntrospectionException
* @throws InvocationTargetException
*/
@Override
public void insertObject(T instance) throws SQLException,
SecurityException, IllegalArgumentException,
InstantiationException, IllegalAccessException,
IntrospectionException, InvocationTargetException {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = databaseConnecter.createConnection();
preparedStatement = connection.prepareStatement(selectQuery);
int i = 0;
for (Field field : type.getDeclaredFields()) {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
field.getName(), type);
Method method = propertyDescriptor
.getReadMethod();
Object value = method.invoke(instance);
preparedStatement.setObject(++i, value);
}
preparedStatement.addBatch();
preparedStatement.executeBatch();
} finally {
MySQLDatabaseResourceCloser.close(preparedStatement);
MySQLDatabaseResourceCloser.close(preparedStatement);
}
}
/**
* Creates a list of <T>s filled with values from the corresponding
* database-table
@ -63,6 +128,7 @@ public class MySQLDatabaseSelecter<T> extends AbstractDatabaseHandler<T> {
* @throws IntrospectionException
* @throws InvocationTargetException
*/
@Override
public List<T> selectObjects() throws SQLException,
SecurityException, IllegalArgumentException,
InstantiationException, IllegalAccessException,
@ -75,7 +141,7 @@ public class MySQLDatabaseSelecter<T> extends AbstractDatabaseHandler<T> {
try {
connection = databaseConnecter.createConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery(query);
resultSet = statement.executeQuery(selectQuery);
return createObjects(resultSet);
@ -86,6 +152,15 @@ public class MySQLDatabaseSelecter<T> extends AbstractDatabaseHandler<T> {
}
}
@Override
protected T selectObject(String uniqueId) throws InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException, IntrospectionException {
// TODO Auto-generated method stub
return null;
}
/**
*
* Creates a list of <T>s filled with values from the provided ResultSet
@ -133,4 +208,5 @@ public class MySQLDatabaseSelecter<T> extends AbstractDatabaseHandler<T> {
}
return list;
}
}

View File

@ -1,95 +0,0 @@
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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.DatabaseConnecter;
/**
*
* Class that inserts a <T> into the corresponding database-table.
*
* @author tastybento
*
* @param <T>
*/
public class MySQLDatabaseInserter<T> extends AbstractDatabaseHandler<T> {
public MySQLDatabaseInserter(BSkyBlock plugin, Class<T> type,
DatabaseConnecter databaseConnecter) {
super(plugin, type, databaseConnecter);
}
@Override
protected String createQuery() {
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO ");
sb.append(type.getSimpleName());
sb.append("(");
sb.append(super.getColumns(false));
sb.append(")");
sb.append(" VALUES (");
sb.append(super.getColumns(true));
sb.append(")");
return sb.toString();
}
/**
* Inserts a <T> into the corresponding database-table
*
* @param instance <T> that should be inserted into the corresponding database-table
* @throws SQLException
* @throws SecurityException
* @throws IllegalArgumentException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IntrospectionException
* @throws InvocationTargetException
*/
public void insertObject(T instance) throws SQLException,
SecurityException, IllegalArgumentException,
InstantiationException, IllegalAccessException,
IntrospectionException, InvocationTargetException {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = databaseConnecter.createConnection();
preparedStatement = connection.prepareStatement(query);
int i = 0;
for (Field field : type.getDeclaredFields()) {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
field.getName(), type);
Method method = propertyDescriptor
.getReadMethod();
Object value = method.invoke(instance);
preparedStatement.setObject(++i, value);
}
preparedStatement.addBatch();
preparedStatement.executeBatch();
} finally {
MySQLDatabaseResourceCloser.close(preparedStatement);
MySQLDatabaseResourceCloser.close(preparedStatement);
}
}
}

View File

@ -2,7 +2,6 @@ package us.tastybento.bskyblock.database.mysql;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.UUID;
import org.bukkit.configuration.file.YamlConfiguration;
@ -29,21 +28,22 @@ public class MySqlDatabaseConnecter implements DatabaseConnecter {
}
@Override
public YamlConfiguration loadYamlFile(String simpleName) {
public String getUniqueId(String tableName) {
// TODO Auto-generated method stub
return null;
}
@Override
public void saveYamlFile(YamlConfiguration config, String simpleName) {
public YamlConfiguration loadYamlFile(String string, String key) {
// TODO Auto-generated method stub
return null;
}
@Override
public UUID getUniqueId() {
public void saveYamlFile(YamlConfiguration yamlFile, String tableName,
String fileName) {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,25 @@
/**
*
*/
package us.tastybento.bskyblock.database.objects;
/**
* Contains fields that must be in any data object
* @author tastybento
*
*/
public abstract class DataObject {
/**
* @return the uniqueId
*/
abstract public String getUniqueId();
/**
* @param uniqueId the uniqueId to set
*/
abstract public void setUniqueId(String uniqueId);
}

View File

@ -21,7 +21,7 @@ import us.tastybento.bskyblock.config.Settings;
* @author Tastybento
* @author Poslovitch
*/
public class Island {
public class Island extends DataObject {
/**
* Island Guard Settings flags
@ -278,11 +278,6 @@ public class Island {
}
//// Island ////
/**
* The unique ID for this island
*/
private UUID uuid;
// The center of the island itself
private Location center;
@ -334,6 +329,8 @@ public class Island {
//// Protection ////
private HashMap<SettingsFlag, Boolean> flags = new HashMap<SettingsFlag, Boolean>();
private String uniqueId = "";
public Island() {};
public Island(Location location, UUID owner, int protectionRange) {
@ -791,17 +788,15 @@ public class Island {
}
}
/**
* @return the uuid
*/
public UUID getUuid() {
return uuid;
@Override
public String getUniqueId() {
return uniqueId;
}
/**
* @param uuid the uuid to set
*/
public void setUuid(UUID uuid) {
this.uuid = uuid;
@Override
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
}

View File

@ -16,7 +16,7 @@ import us.tastybento.bskyblock.config.Settings;
*
* @author tastybento
*/
public class Players {
public class Players extends DataObject {
private HashMap<Integer, Location> homeLocations;
private UUID uuid;
private String playerName;
@ -248,4 +248,16 @@ public class Players {
}
}
@Override
public String getUniqueId() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setUniqueId(String uniqueId) {
// TODO Auto-generated method stub
}
}

View File

@ -1,74 +1,16 @@
package us.tastybento.bskyblock.database.sqlite;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import us.tastybento.bskyblock.BSkyBlock;
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;
public class SQLiteDatabase extends BSBDatabase{
@Override
public Players loadPlayerData(UUID uuid) {
// TODO Auto-generated method stub
public AbstractDatabaseHandler<?> getHandler(BSkyBlock plugin, Class<?> type) {
// return new SQLLiteDatabaseHandler<Island>(plugin, Island.class, new FlatFileDatabaseConnecter(plugin, null));
return null;
}
@Override
public void savePlayerData(Players player) {
// TODO Auto-generated method stub
}
@Override
public Island loadIslandData(String location) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean saveIslandData(Island island) {
// TODO Auto-generated method stub
return false;
}
@Override
public HashMap<UUID, List<String>> loadOfflineHistoryMessages() {
// TODO Auto-generated method stub
return null;
}
@Override
public void saveOfflineHistoryMessages(HashMap<UUID, List<String>> messages) {
// TODO Auto-generated method stub
}
@Override
public boolean isPlayerKnown(UUID uniqueID) {
// TODO Auto-generated method stub
return false;
}
@Override
public UUID getUUID(String name, boolean adminCheck) {
// TODO Auto-generated method stub
return null;
}
@Override
public void savePlayerName(String name, UUID uuid) {
// TODO Auto-generated method stub
}
@Override
public boolean connect(BSkyBlock plugin) {
// TODO Auto-generated method stub
return false;
}
}