Refactored code to make it better to maintain and read.

This commit is contained in:
Tastybento 2018-02-08 21:17:16 -08:00
parent 80f0a78f08
commit f3d7bf2af3
5 changed files with 306 additions and 332 deletions

View File

@ -7,6 +7,7 @@ import java.net.URLClassLoader;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.plugin.InvalidDescriptionException; import org.bukkit.plugin.InvalidDescriptionException;
import us.tastybento.bskyblock.BSkyBlock; import us.tastybento.bskyblock.BSkyBlock;
@ -81,34 +82,34 @@ public class AddonClassLoader extends URLClassLoader {
/** /**
* This is a custom findClass that enables classes in other addons to be found * This is a custom findClass that enables classes in other addons to be found
* (This code was copied from Bukkit's PluginLoader class
* @param name * @param name
* @param checkGlobal * @param checkGlobal
* @return Class * @return Class
* @throws ClassNotFoundException
*/ */
public Class<?> findClass(String name, boolean checkGlobal) throws ClassNotFoundException { public Class<?> findClass(String name, boolean checkGlobal) throws ClassNotFoundException {
if (name.startsWith("us.tastybento.")) { if (name.startsWith("us.tastybento.")) {
throw new ClassNotFoundException(name); throw new ClassNotFoundException(name);
} }
Class<?> result = classes.get(name); return classes.computeIfAbsent(name, k -> createFor(k, checkGlobal));
}
if (result == null) { private Class<?> createFor(String name, boolean checkGlobal) {
if (checkGlobal) { Class<?> result = null;
result = loader.getClassByName(name); if (checkGlobal) {
} result = loader.getClassByName(name);
if (result == null) {
result = super.findClass(name);
if (result != null) {
loader.setClass(name, result);
}
}
classes.put(name, result);
} }
if (result == null) {
try {
result = super.findClass(name);
} catch (ClassNotFoundException e) {
Bukkit.getLogger().severe("Could not find class! " + e.getMessage());
}
if (result != null) {
loader.setClass(name, result);
}
}
return result; return result;
} }

View File

@ -400,11 +400,11 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
@Override @Override
public Command setUsage(String usage) { public Command setUsage(String usage) {
// Go up the chain // Go up the chain
CompositeCommand parent = getParent(); CompositeCommand parentCommand = getParent();
this.usage = getLabel() + " " + usage; this.usage = getLabel() + " " + usage;
while (parent != null) { while (parentCommand != null) {
this.usage = parent.getLabel() + " " + this.usage; this.usage = parentCommand.getLabel() + " " + this.usage;
parent = parent.getParent(); parentCommand = parentCommand.getParent();
} }
this.usage = this.usage.trim(); this.usage = this.usage.trim();
return this; return this;

View File

@ -253,10 +253,8 @@ public class User {
* @return Locale * @return Locale
*/ */
public Locale getLocale() { public Locale getLocale() {
if (sender instanceof Player) { if (sender instanceof Player && !plugin.getPlayers().getLocale(playerUUID).isEmpty()) {
if (!plugin.getPlayers().getLocale(playerUUID).isEmpty()) { return Locale.forLanguageTag(plugin.getPlayers().getLocale(playerUUID));
return Locale.forLanguageTag(plugin.getPlayers().getLocale(playerUUID));
}
} }
return Locale.forLanguageTag(plugin.getSettings().getDefaultLanguage()); return Locale.forLanguageTag(plugin.getSettings().getDefaultLanguage());

View File

@ -21,7 +21,7 @@ public interface ISettings<T> {
// ----------------Saver------------------- // ----------------Saver-------------------
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
default void saveSettings() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, IntrospectionException, SQLException { default void saveSettings() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException, SQLException {
// Get the handler // Get the handler
AbstractDatabaseHandler<T> settingsHandler = (AbstractDatabaseHandler<T>) new FlatFileDatabase().getHandler(getInstance().getClass()); AbstractDatabaseHandler<T> settingsHandler = (AbstractDatabaseHandler<T>) new FlatFileDatabase().getHandler(getInstance().getClass());
// Load every field in the config class // Load every field in the config class
@ -30,7 +30,7 @@ public interface ISettings<T> {
settingsHandler.saveSettings(getInstance()); settingsHandler.saveSettings(getInstance());
} }
default void saveBackup() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, IntrospectionException, SQLException { default void saveBackup() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException, SQLException {
// Save backup // Save backup
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
AbstractDatabaseHandler<T> backupHandler = (AbstractDatabaseHandler<T>) new FlatFileDatabase().getHandler(getInstance().getClass()); AbstractDatabaseHandler<T> backupHandler = (AbstractDatabaseHandler<T>) new FlatFileDatabase().getHandler(getInstance().getClass());
@ -39,7 +39,7 @@ public interface ISettings<T> {
// --------------- Loader ------------------ // --------------- Loader ------------------
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
default T loadSettings() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, ClassNotFoundException, IntrospectionException, SQLException { default T loadSettings() throws InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, IntrospectionException, SQLException {
// See if this settings object already exists in the database // See if this settings object already exists in the database
AbstractDatabaseHandler<T> dbhandler = (AbstractDatabaseHandler<T>) BSBDatabase.getDatabase().getHandler(getClass()); AbstractDatabaseHandler<T> dbhandler = (AbstractDatabaseHandler<T>) BSBDatabase.getDatabase().getHandler(getClass());
T dbConfig = null; T dbConfig = null;

View File

@ -32,7 +32,6 @@ import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import us.tastybento.bskyblock.api.configuration.ConfigEntry;
import us.tastybento.bskyblock.database.DatabaseConnecter; import us.tastybento.bskyblock.database.DatabaseConnecter;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler; import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.objects.adapters.Adapter; import us.tastybento.bskyblock.database.objects.adapters.Adapter;
@ -124,74 +123,78 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
* @throws SQLException * @throws SQLException
*/ */
private void createSchema() throws IntrospectionException, SQLException { private void createSchema() throws IntrospectionException, SQLException {
PreparedStatement pstmt = null; StringBuilder sql = new StringBuilder();
try { sql.append("CREATE TABLE IF NOT EXISTS `");
String sql = "CREATE TABLE IF NOT EXISTS `" + dataObject.getCanonicalName() + "` ("; sql.append(dataObject.getCanonicalName());
// Run through the fields of the class using introspection sql.append("` (");
for (Field field : dataObject.getDeclaredFields()) { // Run through the fields of the class using introspection
// Get the description of the field for (Field field : dataObject.getDeclaredFields()) {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject); // Get the description of the field
//plugin.getLogger().info("DEBUG: Field = " + field.getName() + "(" + propertyDescriptor.getPropertyType().getTypeName() + ")"); PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
// Get default SQL mappings //plugin.getLogger().info("DEBUG: Field = " + field.getName() + "(" + propertyDescriptor.getPropertyType().getTypeName() + ")");
// Get the write method for this field. This method will take an argument of the type of this field. // Get default SQL mappings
Method writeMethod = propertyDescriptor.getWriteMethod(); // Get the write method for this field. This method will take an argument of the type of this field.
// The SQL column name is the name of the field Method writeMethod = propertyDescriptor.getWriteMethod();
String columnName = field.getName(); // The SQL column name is the name of the field
// Get the mapping for this field from the hashmap String columnName = field.getName();
String typeName = propertyDescriptor.getPropertyType().getTypeName(); // Get the mapping for this field from the hashmap
if (propertyDescriptor.getPropertyType().isEnum()) { String typeName = propertyDescriptor.getPropertyType().getTypeName();
typeName = "Enum"; if (propertyDescriptor.getPropertyType().isEnum()) {
} typeName = "Enum";
String mapping = mySQLmapping.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 += "`" + columnName + "` " + mapping + ",";
// 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
String setSql = "CREATE TABLE IF NOT EXISTS `" + dataObject.getCanonicalName() + "." + field.getName() + "` ("
+ "uniqueId VARCHAR(36) NOT NULL, ";
// Get columns separated by commas
setSql += getCollectionColumnString(writeMethod,false,true);
// Close the SQL string
setSql += ")";
//plugin.getLogger().info(setSql);
// Execute the statement
try (PreparedStatement collections = connection.prepareStatement(setSql)) {
if (DEBUG) {
plugin.getLogger().info("DEBUG: collections prepared statement = " + collections.toString());
}
collections.executeUpdate();
}
}
} 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 += field.getName() + " VARCHAR(254),";
plugin.getLogger().severe("Unknown type! Hoping it'll fit in a string!");
plugin.getLogger().severe(propertyDescriptor.getPropertyType().getTypeName());
}
} }
//plugin.getLogger().info("DEBUG: SQL before trim string = " + sql); String mapping = mySQLmapping.get(typeName);
// For the main table for the class, the unique ID is the primary key // If it exists, then create the SQL
sql += " PRIMARY KEY (uniqueId))"; if (mapping != null) {
//plugin.getLogger().info("DEBUG: SQL string = " + sql); // Note that the column name must be enclosed in `'s because it may include reserved words.
// Prepare and execute the database statements sql.append("`");
pstmt = connection.prepareStatement(sql); 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())) {
if (DEBUG) {
plugin.getLogger().info("DEBUG: collections prepared statement = " + collections.toString());
}
collections.executeUpdate();
}
}
} 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(" VARCHAR(254),");
plugin.getLogger().severe("Unknown type! Hoping it'll fit in a string!");
plugin.getLogger().severe(propertyDescriptor.getPropertyType().getTypeName());
}
}
//plugin.getLogger().info("DEBUG: SQL before trim string = " + sql);
// For the main table for the class, the unique ID is the primary key
sql.append(" PRIMARY KEY (uniqueId))");
//plugin.getLogger().info("DEBUG: SQL string = " + sql);
// Prepare and execute the database statements
try (PreparedStatement pstmt = connection.prepareStatement(sql.toString())) {
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: pstmt = " + pstmt.toString()); plugin.getLogger().info("DEBUG: pstmt = " + pstmt.toString());
} }
pstmt.executeUpdate(); pstmt.executeUpdate();
} catch (Exception e) {
plugin.getLogger().severe("Could not create database schema! " + e.getMessage());
} finally {
// Close the database properly
MySQLDatabaseResourceCloser.close(pstmt);
} }
} }
@ -271,11 +274,13 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
private List<String> getCollentionColumnList(Method method, boolean createSchema) { private List<String> getCollentionColumnList(Method method, boolean createSchema) {
List<String> columns = new ArrayList<>(); List<String> columns = new ArrayList<>();
for (Entry<String,String> en : getCollectionColumnMap(method).entrySet()) { for (Entry<String,String> en : getCollectionColumnMap(method).entrySet()) {
String col = en.getKey(); StringBuilder col = new StringBuilder();
col.append(en.getKey());
if (createSchema) { if (createSchema) {
col += " " + en.getValue(); col.append(" ");
col.append(en.getValue());
} }
columns.add(col); columns.add(col.toString());
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: collection columns = " + col); plugin.getLogger().info("DEBUG: collection columns = " + col);
} }
@ -307,6 +312,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
for (Type type : parameters) { for (Type type : parameters) {
// This is a request for column names. // This is a request for column names.
String setMapping = mySQLmapping.get(type.getTypeName()); String setMapping = mySQLmapping.get(type.getTypeName());
// This column name format is typeName_# where # is a number incremented from 0
columns.put("`" + type.getTypeName() + "_" + index + "`", setMapping != null ? setMapping : "VARCHAR(254)"); columns.put("`" + type.getTypeName() + "_" + index + "`", setMapping != null ? setMapping : "VARCHAR(254)");
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: collection column = " + "`" + type.getTypeName() + "_" + index + "`" + setMapping); plugin.getLogger().info("DEBUG: collection column = " + "`" + type.getTypeName() + "_" + index + "`" + setMapping);
@ -388,171 +394,169 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
InstantiationException, IllegalAccessException, InstantiationException, IllegalAccessException,
IntrospectionException, InvocationTargetException, NoSuchMethodException { IntrospectionException, InvocationTargetException, NoSuchMethodException {
Connection connection = null;
PreparedStatement preparedStatement = null;
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: saveObject "); plugin.getLogger().info("DEBUG: saveObject ");
} }
try { // Try to connect to the database
// Try to connect to the database try (Connection connection = databaseConnecter.createConnection()) {
connection = databaseConnecter.createConnection();
// insertQuery is created in super from the createInsertQuery() method // insertQuery is created in super from the createInsertQuery() method
preparedStatement = connection.prepareStatement(insertQuery); try (PreparedStatement preparedStatement = connection.prepareStatement(insertQuery)) {
// Get the uniqueId. As each class extends DataObject, it must have this method in it. // Get the uniqueId. As each class extends DataObject, it must have this method in it.
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", dataObject); PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", dataObject);
Method getUniqueId = propertyDescriptor.getReadMethod(); Method getUniqueId = propertyDescriptor.getReadMethod();
final String uniqueId = (String) getUniqueId.invoke(instance); final String uniqueId = (String) getUniqueId.invoke(instance);
if (DEBUG) {
plugin.getLogger().info("DEBUG: Unique Id = " + uniqueId);
}
if (uniqueId.isEmpty()) {
throw new SQLException("uniqueId is blank");
}
// Create the insertion
int i = 0;
if (DEBUG) {
plugin.getLogger().info("DEBUG: insert Query " + insertQuery);
}
// 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();
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: Field = " + field.getName() + "(" + propertyDescriptor.getPropertyType().getTypeName() + ")"); plugin.getLogger().info("DEBUG: Unique Id = " + uniqueId);
} }
//sql += "`" + field.getName() + "` " + mapping + ","; if (uniqueId.isEmpty()) {
// Invoke the read method to obtain the value from the class - this is the value we need to store in the database throw new SQLException("uniqueId is blank");
Object value = method.invoke(instance); }
// Create the insertion
int i = 0;
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: value = " + value); plugin.getLogger().info("DEBUG: insert Query " + insertQuery);
} }
// Adapter // Run through the fields in the class using introspection
// Check if there is an annotation on the field for (Field field : dataObject.getDeclaredFields()) {
ConfigEntry configEntry = field.getAnnotation(ConfigEntry.class); // Get the field's property descriptor
// If there is a config annotation then do something propertyDescriptor = new PropertyDescriptor(field.getName(), dataObject);
if (configEntry != null) { // Get the read method for this field
Method method = propertyDescriptor.getReadMethod();
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: there is a configEntry"); plugin.getLogger().info("DEBUG: Field = " + field.getName() + "(" + propertyDescriptor.getPropertyType().getTypeName() + ")");
} }
} //sql += "`" + field.getName() + "` " + mapping + ",";
Adapter adapterNotation = field.getAnnotation(Adapter.class); // Invoke the read method to obtain the value from the class - this is the value we need to store in the database
if (adapterNotation != null && AdapterInterface.class.isAssignableFrom(adapterNotation.value())) { Object value = method.invoke(instance);
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: there is an adapter"); plugin.getLogger().info("DEBUG: value = " + value);
} }
// A conversion adapter has been defined // Adapter Notation
value = ((AdapterInterface<?,?>)adapterNotation.value().newInstance()).deserialize(value); Adapter adapterNotation = field.getAnnotation(Adapter.class);
if (DEBUG) { if (adapterNotation != null && AdapterInterface.class.isAssignableFrom(adapterNotation.value())) {
plugin.getLogger().info("DEBUG: value now after deserialization = " + 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
String clearTableSql = "DELETE FROM `" + dataObject.getCanonicalName() + "." + field.getName() + "` WHERE uniqueId = ?";
try (PreparedStatement collStatement = connection.prepareStatement(clearTableSql)) {
collStatement.setString(1, uniqueId);
collStatement.execute();
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: collStatement " + collStatement.toString()); plugin.getLogger().info("DEBUG: there is an adapter");
}
// A conversion adapter has been defined
value = ((AdapterInterface<?,?>)adapterNotation.value().newInstance()).deserialize(value);
if (DEBUG) {
plugin.getLogger().info("DEBUG: value now after deserialization = " + value);
} }
} }
// Insert into the table // Create set and map table inserts if this is a Collection
String setSql = "INSERT INTO `" + dataObject.getCanonicalName() + "." + field.getName() + "` (uniqueId, "; if (propertyDescriptor.getPropertyType().equals(Set.class) ||
// Get the columns we are going to insert, just the names of them propertyDescriptor.getPropertyType().equals(Map.class) ||
setSql += getCollectionColumnString(propertyDescriptor.getWriteMethod(), false, false) + ") "; propertyDescriptor.getPropertyType().equals(HashMap.class) ||
// Get all the ?'s for the columns propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
setSql += "VALUES ('?'," + getCollectionColumnString(propertyDescriptor.getWriteMethod(), true, false) + ")"; // Collection
// Prepare the statement // The table is cleared for this uniqueId every time the data is stored
try (PreparedStatement collStatement = connection.prepareStatement(setSql)) { StringBuilder clearTableSql = new StringBuilder();
// Set the uniqueId clearTableSql.append("DELETE FROM `");
collStatement.setString(1, uniqueId); clearTableSql.append(dataObject.getCanonicalName());
if (DEBUG) { clearTableSql.append(".");
plugin.getLogger().info("DEBUG: collection insert =" + setSql); clearTableSql.append(field.getName());
} clearTableSql.append("` WHERE uniqueId = ?");
// Do single dimension types (set and list) try (PreparedStatement collStatement = connection.prepareStatement(clearTableSql.toString())) {
if (propertyDescriptor.getPropertyType().equals(Set.class) || collStatement.setString(1, uniqueId);
propertyDescriptor.getPropertyType().equals(ArrayList.class)) { collStatement.execute();
//plugin.getLogger().info("DEBUG: set class for "); if (DEBUG) {
// Loop through the set or list plugin.getLogger().info("DEBUG: collStatement " + collStatement.toString());
// 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);
if (DEBUG) {
plugin.getLogger().info("DEBUG: " + collStatement.toString());
}
// 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();
if (DEBUG) {
plugin.getLogger().info("DEBUG: entry ket = " + en.getKey());
}
// Get the key and serialize it
Object key = serialize(en.getKey(), en.getKey().getClass());
if (DEBUG) {
plugin.getLogger().info("DEBUG: key class = " + en.getKey().getClass().getTypeName());
}
// Get the value and serialize it
Object mapValue = serialize(en.getValue(), en.getValue().getClass());
if (DEBUG) {
plugin.getLogger().info("DEBUG: mapValue = " + mapValue);
}
// Write the objects into prepared statement
collStatement.setObject(1, key);
collStatement.setObject(2, mapValue);
if (DEBUG) {
plugin.getLogger().info("DEBUG: " + collStatement.toString());
}
// 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 // Insert into the table
// additional table. StringBuilder setSql = new StringBuilder();
value = true; setSql.append("INSERT INTO `");
} setSql.append(dataObject.getCanonicalName());
} else { setSql.append(".");
// If the value is not a collection, it just needs to be serialized to go into the database. setSql.append(field.getName());
value = serialize(value, propertyDescriptor.getPropertyType()); setSql.append("` (uniqueId, ");
} // Get the columns we are going to insert, just the names of them
// Set the value in the main prepared statement and increment the location setSql.append(getCollectionColumnString(propertyDescriptor.getWriteMethod(), false, false));
// Note that with prepared statements, they count from 1, not 0, so the ++ goes on the front of i. setSql.append(") ");
preparedStatement.setObject(++i, value); // Get all the ?'s for the columns
} setSql.append("VALUES ('?',");
// Add the statements to a batch setSql.append(getCollectionColumnString(propertyDescriptor.getWriteMethod(), true, false));
preparedStatement.addBatch(); setSql.append(")");
// Execute // Prepare the statement
if (DEBUG) { try (PreparedStatement collStatement = connection.prepareStatement(setSql.toString())) {
plugin.getLogger().info("DEBUG: prepared statement = " + preparedStatement.toString()); // Set the uniqueId
} collStatement.setString(1, uniqueId);
preparedStatement.executeBatch(); if (DEBUG) {
plugin.getLogger().info("DEBUG: collection insert =" + setSql);
}
// 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);
if (DEBUG) {
plugin.getLogger().info("DEBUG: " + collStatement.toString());
}
// 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();
if (DEBUG) {
plugin.getLogger().info("DEBUG: entry ket = " + en.getKey());
}
} finally { // Get the key and serialize it
// Close properly Object key = serialize(en.getKey(), en.getKey().getClass());
MySQLDatabaseResourceCloser.close(connection); if (DEBUG) {
MySQLDatabaseResourceCloser.close(preparedStatement); plugin.getLogger().info("DEBUG: key class = " + en.getKey().getClass().getTypeName());
}
// Get the value and serialize it
Object mapValue = serialize(en.getValue(), en.getValue().getClass());
if (DEBUG) {
plugin.getLogger().info("DEBUG: mapValue = " + mapValue);
}
// Write the objects into prepared statement
collStatement.setObject(1, key);
collStatement.setObject(2, mapValue);
if (DEBUG) {
plugin.getLogger().info("DEBUG: " + collStatement.toString());
}
// 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
if (DEBUG) {
plugin.getLogger().info("DEBUG: prepared statement = " + preparedStatement.toString());
}
preparedStatement.executeBatch();
}
} }
} }
@ -617,27 +621,14 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
InstantiationException, IllegalAccessException, InstantiationException, IllegalAccessException,
IntrospectionException, InvocationTargetException, ClassNotFoundException { IntrospectionException, InvocationTargetException, ClassNotFoundException {
Connection connection = null; try (Connection conn = databaseConnecter.createConnection();
Statement statement = null; Statement statement = conn.createStatement();
ResultSet resultSet = null; ResultSet resultSet = statement.executeQuery(selectQuery)) {
try {
connection = databaseConnecter.createConnection();
statement = connection.createStatement();
if (DEBUG) {
plugin.getLogger().info("DEBUG: selectQuery = " + selectQuery);
}
resultSet = statement.executeQuery(selectQuery);
return createObjects(resultSet); return createObjects(resultSet);
} finally {
MySQLDatabaseResourceCloser.close(resultSet);
MySQLDatabaseResourceCloser.close(statement);
MySQLDatabaseResourceCloser.close(connection);
} }
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#selectObject(java.lang.String) * @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#selectObject(java.lang.String)
*/ */
@ -645,32 +636,33 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
public T loadObject(String uniqueId) throws InstantiationException, public T loadObject(String uniqueId) throws InstantiationException,
IllegalAccessException, IllegalArgumentException, IllegalAccessException, IllegalArgumentException,
InvocationTargetException, IntrospectionException, SQLException, SecurityException, ClassNotFoundException { InvocationTargetException, IntrospectionException, SQLException, SecurityException, ClassNotFoundException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: loading object for " + uniqueId); plugin.getLogger().info("DEBUG: loading object for " + uniqueId);
} }
try { try (Connection conn = databaseConnecter.createConnection()) {
connection = databaseConnecter.createConnection(); // Build the select query
String query = "SELECT " + getColumns(false) + " FROM `" + dataObject.getCanonicalName() + "` WHERE uniqueId = ? LIMIT 1"; StringBuilder query = new StringBuilder();
try (PreparedStatement preparedStatement = connection.prepareStatement(query)) { query.append("SELECT ");
query.append(getColumns(false));
query.append(" FROM `");
query.append(dataObject.getCanonicalName());
query.append("` WHERE uniqueId = ? LIMIT 1");
try (PreparedStatement preparedStatement = conn.prepareStatement(query.toString())) {
preparedStatement.setString(1, uniqueId); preparedStatement.setString(1, uniqueId);
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: load Object query = " + preparedStatement.toString()); plugin.getLogger().info("DEBUG: load Object query = " + preparedStatement.toString());
} }
resultSet = preparedStatement.executeQuery(); try (ResultSet resultSet = preparedStatement.executeQuery()) {
// If there is a result, we only want/need the first one
List<T> result = createObjects(resultSet); List<T> result = createObjects(resultSet);
if (!result.isEmpty()) { if (!result.isEmpty()) {
return result.get(0); return result.get(0);
}
} }
} }
return null; return null;
} finally {
MySQLDatabaseResourceCloser.close(resultSet);
MySQLDatabaseResourceCloser.close(statement);
MySQLDatabaseResourceCloser.close(connection);
} }
} }
@ -732,14 +724,20 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
} }
// TODO Get the values from the subsidiary tables. // TODO Get the values from the subsidiary tables.
// value is just of type boolean right now // value is just of type boolean right now
String setSql = "SELECT "; StringBuilder setSql = new StringBuilder();
setSql.append("SELECT ");
// Get the columns, just the names of them, no ?'s or types // Get the columns, just the names of them, no ?'s or types
setSql += getCollectionColumnString(method, false, false) + " "; setSql.append(getCollectionColumnString(method, false, false));
setSql += "FROM `" + dataObject.getCanonicalName() + "." + field.getName() + "` "; 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 // We will need to fill in the ? later with the unique id of the class from the database
setSql += "WHERE uniqueId = ?"; setSql.append("WHERE uniqueId = ?");
// Prepare the statement // Prepare the statement
try (PreparedStatement collStatement = connection.prepareStatement(setSql)) { try (PreparedStatement collStatement = connection.prepareStatement(setSql.toString())) {
// Set the unique ID // Set the unique ID
collStatement.setObject(1, uniqueId); collStatement.setObject(1, uniqueId);
if (DEBUG) { if (DEBUG) {
@ -778,8 +776,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
value = new ArrayList<>(); value = new ArrayList<>();
//plugin.getLogger().info("DEBUG: collection type argument = " + collectionTypes); //plugin.getLogger().info("DEBUG: collection type argument = " + collectionTypes);
while (collectionResultSet.next()) { while (collectionResultSet.next()) {
//plugin.getLogger().info("DEBUG: adding to the list"); // Add to the list
//plugin.getLogger().info("DEBUG: collectionResultSet size = " + collectionResultSet.getFetchSize());
((List<Object>) value).add(deserialize(collectionResultSet.getObject(1),Class.forName(setType.getTypeName()))); ((List<Object>) value).add(deserialize(collectionResultSet.getObject(1),Class.forName(setType.getTypeName())));
} }
} else if (Map.class.isAssignableFrom(propertyDescriptor.getPropertyType()) || } else if (Map.class.isAssignableFrom(propertyDescriptor.getPropertyType()) ||
@ -829,15 +826,6 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
} }
// Adapter // Adapter
// Check if there is an annotation on the field // Check if there is an annotation on the field
ConfigEntry configEntry = field.getAnnotation(ConfigEntry.class);
// If there is a config annotation then do something
if (configEntry != null) {
if (DEBUG)
{
plugin.getLogger().info("DEBUG: there is a configEntry");
// TODO: add config entry handling
}
}
Adapter adapterNotation = field.getAnnotation(Adapter.class); Adapter adapterNotation = field.getAnnotation(Adapter.class);
if (adapterNotation != null && AdapterInterface.class.isAssignableFrom(adapterNotation.value())) { if (adapterNotation != null && AdapterInterface.class.isAssignableFrom(adapterNotation.value())) {
if (DEBUG) { if (DEBUG) {
@ -917,12 +905,11 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
throws IllegalAccessException, IllegalArgumentException, throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, IntrospectionException, SQLException, NoSuchMethodException, SecurityException { InvocationTargetException, IntrospectionException, SQLException, NoSuchMethodException, SecurityException {
// Delete this object from all tables // Delete this object from all tables
Connection connection = null;
PreparedStatement preparedStatement = null;
try { //PreparedStatement preparedStatement = null;
// Try to connect to the database
connection = databaseConnecter.createConnection(); // 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. // Get the uniqueId. As each class extends DataObject, it must have this method in it.
Method getUniqueId = dataObject.getMethod("getUniqueId"); Method getUniqueId = dataObject.getMethod("getUniqueId");
String uniqueId = (String) getUniqueId.invoke(instance); String uniqueId = (String) getUniqueId.invoke(instance);
@ -933,14 +920,16 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
// Delete from the main table // Delete from the main table
// First substitution is the table name // First substitution is the table name
// deleteQuery is created in super from the createInsertQuery() method // deleteQuery is created in super from the createInsertQuery() method
preparedStatement = connection.prepareStatement(deleteQuery.replace("[table_name]", "`" + dataObject.getCanonicalName() + "`")); try (PreparedStatement preparedStatement = conn.prepareStatement(deleteQuery.replace("[table_name]", "`" + dataObject.getCanonicalName() + "`"))) {
// Second is the unique ID // Second is the unique ID
preparedStatement.setString(1, uniqueId); preparedStatement.setString(1, uniqueId);
preparedStatement.addBatch(); preparedStatement.addBatch();
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: DELETE Query " + preparedStatement.toString()); plugin.getLogger().info("DEBUG: DELETE Query " + preparedStatement.toString());
}
preparedStatement.executeBatch();
} }
preparedStatement.executeBatch();
// Delete from any sub tables created from the object // Delete from any sub tables created from the object
// Run through the fields in the class using introspection // Run through the fields in the class using introspection
for (Field field : dataObject.getDeclaredFields()) { for (Field field : dataObject.getDeclaredFields()) {
@ -952,7 +941,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
propertyDescriptor.getPropertyType().equals(HashMap.class) || propertyDescriptor.getPropertyType().equals(HashMap.class) ||
propertyDescriptor.getPropertyType().equals(ArrayList.class)) { propertyDescriptor.getPropertyType().equals(ArrayList.class)) {
// First substitution is the table name // First substitution is the table name
try (PreparedStatement preparedStatement2 = connection.prepareStatement(deleteQuery.replace("[table_name]", "`" + dataObject.getCanonicalName() + "." + field.getName() + "`"))) { try (PreparedStatement preparedStatement2 = conn.prepareStatement(deleteQuery.replace("[table_name]", "`" + dataObject.getCanonicalName() + "." + field.getName() + "`"))) {
// Second is the unique ID // Second is the unique ID
preparedStatement2.setString(1, uniqueId); preparedStatement2.setString(1, uniqueId);
preparedStatement2.addBatch(); preparedStatement2.addBatch();
@ -964,12 +953,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
} }
} }
} }
} finally { }
// Close properly
MySQLDatabaseResourceCloser.close(preparedStatement);
MySQLDatabaseResourceCloser.close(connection);
}
} }
/* (non-Javadoc) /* (non-Javadoc)
@ -980,31 +964,22 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
if (DEBUG) { if (DEBUG) {
plugin.getLogger().info("DEBUG: checking if " + key + " exists in the database"); plugin.getLogger().info("DEBUG: checking if " + key + " exists in the database");
} }
Connection connection = null; // Create the query to see if this key exists
PreparedStatement preparedStatement = null; StringBuilder query = new StringBuilder();
ResultSet resultSet = null; query.append("SELECT IF ( EXISTS( SELECT * FROM `");
String query = "SELECT IF ( EXISTS( SELECT * FROM `" + dataObject.getCanonicalName() + "` WHERE `uniqueId` = ?), 1, 0)"; query.append(dataObject.getCanonicalName());
//String query = "SELECT * FROM `" + type.getCanonicalName() + "` WHERE uniqueId = ?"; query.append("` WHERE `uniqueId` = ?), 1, 0)");
try {
connection = databaseConnecter.createConnection(); try (Connection conn = databaseConnecter.createConnection();
preparedStatement = connection.prepareStatement(query); PreparedStatement preparedStatement = conn.prepareStatement(query.toString())) {
preparedStatement.setString(1, key); preparedStatement.setString(1, key);
resultSet = preparedStatement.executeQuery(); try (ResultSet resultSet = preparedStatement.executeQuery()) {
if (DEBUG) { if (resultSet.next()) {
plugin.getLogger().info("DEBUG: object exists sql " + preparedStatement.toString()); return resultSet.getBoolean(1);
}
if (resultSet.next()) {
if (DEBUG) {
plugin.getLogger().info("DEBUG: result is " + resultSet.getBoolean(1));
} }
return resultSet.getBoolean(1);
} }
} catch (SQLException e) { } catch (SQLException e) {
plugin.getLogger().severe("Could not check if key exists in database! " + key + " " + e.getMessage()); plugin.getLogger().severe("Could not check if key exists in database! " + key + " " + e.getMessage());
} finally {
MySQLDatabaseResourceCloser.close(resultSet);
MySQLDatabaseResourceCloser.close(preparedStatement);
MySQLDatabaseResourceCloser.close(connection);
} }
return false; return false;
} }
@ -1012,14 +987,14 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
@Override @Override
public void saveSettings(T instance) public void saveSettings(T instance)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException { throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
plugin.getLogger().severe("This method should not be used because configs are not stored in MySQL"); // This method should not be used because configs are not stored in MySQL
} }
@Override @Override
public T loadSettings(String uniqueId, T dbConfig) throws InstantiationException, IllegalAccessException, public T loadSettings(String uniqueId, T dbConfig) throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IntrospectionException { IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IntrospectionException {
plugin.getLogger().severe("This method should not be used because configs are not stored in MySQL"); // This method should not be used because configs are not stored in MySQL
return null; return null;
} }