mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2025-02-02 21:41:45 +01:00
Adds support for MongoDB.
Needs more testing, but seems to work. The main problem is that it pulls in the MongoDB Java driver which boosts the size of the JAR to 2.3MB. It may be better to put the Mongo driver into an addon so that only Mongo users have to have the larger JAR.
This commit is contained in:
parent
17ecb1c0d4
commit
4100edd279
@ -48,8 +48,10 @@ general:
|
||||
|
||||
### Database-related Settings ###
|
||||
database:
|
||||
# FLATFILE, MYSQL
|
||||
# FLATFILE, MYSQL, MONGO
|
||||
type: FLATFILE
|
||||
host: localhost
|
||||
# Port 3306 is MySQL's default. Port 27017 is MongoDB's default.
|
||||
port: 3306
|
||||
name: BSkyBlock
|
||||
username: username
|
||||
|
26
pom.xml
26
pom.xml
@ -61,6 +61,27 @@
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>us.tastybento.bskyblock.BSkyBlock</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- I'm going to comment out these sections for now to speed up compilation
|
||||
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.0.1</version> <executions> <execution> <id>attach-sources</id>
|
||||
@ -163,6 +184,11 @@
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver</artifactId>
|
||||
<version>3.6.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
|
@ -80,4 +80,5 @@ public abstract class AbstractDatabaseHandler<T> {
|
||||
*/
|
||||
public abstract boolean objectExists(String key);
|
||||
|
||||
public abstract void close();
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package us.tastybento.bskyblock.database;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase;
|
||||
import us.tastybento.bskyblock.database.mongodb.MongoDBDatabase;
|
||||
import us.tastybento.bskyblock.database.mysql.MySQLDatabase;
|
||||
|
||||
public abstract class BSBDatabase {
|
||||
@ -22,7 +23,8 @@ public abstract class BSBDatabase {
|
||||
|
||||
public enum DatabaseType{
|
||||
FLATFILE(new FlatFileDatabase()),
|
||||
MYSQL(new MySQLDatabase());
|
||||
MYSQL(new MySQLDatabase()),
|
||||
MONGO(new MongoDBDatabase());
|
||||
|
||||
BSBDatabase database;
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package us.tastybento.bskyblock.database;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
@ -17,8 +16,13 @@ public interface DatabaseConnecter {
|
||||
*
|
||||
* @return A new connection to the database using the settings provided
|
||||
*/
|
||||
Connection createConnection();
|
||||
|
||||
Object createConnection();
|
||||
|
||||
/**
|
||||
* Close the database connection
|
||||
*/
|
||||
void closeConnection();
|
||||
|
||||
/**
|
||||
* Returns the connection url
|
||||
*
|
||||
|
@ -162,4 +162,9 @@ public class FlatFileDatabaseConnecter implements DatabaseConnecter {
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
// Not used
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -448,4 +448,10 @@ public class FlatFileDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// Not used
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
22
src/main/java/us/tastybento/bskyblock/database/mongodb/MongoDBDatabase.java
Executable file
22
src/main/java/us/tastybento/bskyblock/database/mongodb/MongoDBDatabase.java
Executable file
@ -0,0 +1,22 @@
|
||||
package us.tastybento.bskyblock.database.mongodb;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.database.AbstractDatabaseHandler;
|
||||
import us.tastybento.bskyblock.database.BSBDatabase;
|
||||
import us.tastybento.bskyblock.database.DatabaseConnectionSettingsImpl;
|
||||
|
||||
public class MongoDBDatabase extends BSBDatabase{
|
||||
|
||||
@Override
|
||||
public AbstractDatabaseHandler<?> getHandler(Class<?> type) {
|
||||
BSkyBlock plugin = BSkyBlock.getInstance();
|
||||
return new MongoDBDatabaseHandler<>(plugin, type, new MongoDBDatabaseConnecter(new DatabaseConnectionSettingsImpl(
|
||||
plugin.getSettings().getDbHost(),
|
||||
plugin.getSettings().getDbPort(),
|
||||
plugin.getSettings().getDbName(),
|
||||
plugin.getSettings().getDbUsername(),
|
||||
plugin.getSettings().getDbPassword()
|
||||
)));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package us.tastybento.bskyblock.database.mongodb;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientOptions;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
|
||||
import us.tastybento.bskyblock.database.DatabaseConnecter;
|
||||
import us.tastybento.bskyblock.database.DatabaseConnectionSettingsImpl;
|
||||
|
||||
public class MongoDBDatabaseConnecter implements DatabaseConnecter {
|
||||
|
||||
private MongoClient client;
|
||||
private MongoCredential credential;
|
||||
private DatabaseConnectionSettingsImpl dbSettings;
|
||||
|
||||
/**
|
||||
* Class for MySQL database connections using the settings provided
|
||||
* @param dbSettings
|
||||
*/
|
||||
public MongoDBDatabaseConnecter(DatabaseConnectionSettingsImpl dbSettings) {
|
||||
this.dbSettings = dbSettings;
|
||||
credential = MongoCredential.createCredential(dbSettings.getUsername(),
|
||||
dbSettings.getDatabaseName(),
|
||||
dbSettings.getPassword().toCharArray());
|
||||
MongoClientOptions options = MongoClientOptions.builder().sslEnabled(false).build();
|
||||
client = new MongoClient(new ServerAddress(dbSettings.getHost(), dbSettings.getPort()),credential,options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MongoDatabase createConnection() {
|
||||
MongoDatabase database = client.getDatabase(dbSettings.getDatabaseName());
|
||||
return database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionUrl() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId(String tableName) {
|
||||
// Not used
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration loadYamlFile(String string, String key) {
|
||||
// Not used
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean uniqueIdExists(String tableName, String key) {
|
||||
// Not used
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveYamlFile(YamlConfiguration yamlConfig, String tableName, String fileName,
|
||||
Map<String, String> commentMap) {
|
||||
// Not used
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
client.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
package us.tastybento.bskyblock.database.mongodb;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.MongoCursor;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import com.mongodb.client.model.IndexOptions;
|
||||
import com.mongodb.client.model.Indexes;
|
||||
import com.mongodb.util.JSON;
|
||||
|
||||
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.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;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class that inserts a <T> into the corresponding database-table.
|
||||
*
|
||||
* @author tastybento
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MongoDBDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
|
||||
/**
|
||||
* Connection to the database
|
||||
*/
|
||||
private MongoDatabase database = null;
|
||||
private MongoCollection<Document> collection;
|
||||
private DatabaseConnecter databaseConnecter;
|
||||
|
||||
private BSkyBlock bskyblock;
|
||||
|
||||
/**
|
||||
* Handles the connection to the database and creation of the initial database schema (tables) for
|
||||
* the class that will be stored.
|
||||
* @param plugin - BSkyBlock plugin object
|
||||
* @param type - the type of class to be stored in the database. Must inherit DataObject
|
||||
* @param databaseConnecter - authentication details for the database
|
||||
*/
|
||||
public MongoDBDatabaseHandler(BSkyBlock plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
|
||||
super(plugin, type, databaseConnecter);
|
||||
this.bskyblock = plugin;
|
||||
this.databaseConnecter = databaseConnecter;
|
||||
database = (MongoDatabase)databaseConnecter.createConnection();
|
||||
collection = database.getCollection(dataObject.getCanonicalName());
|
||||
IndexOptions indexOptions = new IndexOptions().unique(true);
|
||||
collection.createIndex(Indexes.text("uniqueId"), indexOptions);
|
||||
}
|
||||
|
||||
// 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
|
||||
public List<T> loadObjects() {
|
||||
List<T> list = new ArrayList<>();
|
||||
Gson gson = getGSON();
|
||||
MongoCursor<Document> it = collection.find(new Document()).iterator();
|
||||
while (it.hasNext()) {
|
||||
// The deprecated serialize option does not have a viable alternative without involving a huge amount of custom code
|
||||
String json = JSON.serialize(it.next());
|
||||
//String json = it.next().toJson();
|
||||
Bukkit.getLogger().info("DEBUG: " + json);
|
||||
json = json.replaceFirst("_id", "uniqueId");
|
||||
Bukkit.getLogger().info("DEBUG: " + json);
|
||||
|
||||
list.add(gson.fromJson(json, dataObject));
|
||||
}
|
||||
Bukkit.getLogger().info("DEBUG: list is " + list.size());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T loadObject(String uniqueId) {
|
||||
Document doc = collection.find(new Document("_id", uniqueId)).limit(1).first();
|
||||
if (doc != null) {
|
||||
Gson gson = getGSON();
|
||||
String json = JSON.serialize(doc).replaceFirst("_id", "uniqueId");
|
||||
Bukkit.getLogger().info("DEBUG:loading single object: " + json);
|
||||
return gson.fromJson(json, dataObject);
|
||||
}
|
||||
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;
|
||||
}
|
||||
try {
|
||||
Gson gson = getGSON();
|
||||
String toStore = gson.toJson(instance);
|
||||
// Change uniqueId to _id
|
||||
toStore = toStore.replaceFirst("uniqueId", "_id");
|
||||
Bukkit.getLogger().info("DEBUG: Saving " + toStore);
|
||||
Document document = Document.parse(toStore);
|
||||
collection.insertOne(document);
|
||||
} catch (Exception 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;
|
||||
}
|
||||
try {
|
||||
Method getUniqueId = dataObject.getMethod("getUniqueId");
|
||||
String uniqueId = (String) getUniqueId.invoke(instance);
|
||||
collection.findOneAndDelete(new Document("_id", uniqueId));
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe(() -> "Could not delete object " + instance.getClass().getName() + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#objectExists(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean objectExists(String key) {
|
||||
return collection.find(new Document("_id", key)).limit(1).first() != null ? true : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
databaseConnecter.closeConnection();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ public class MySQLDatabaseConnecter implements DatabaseConnecter {
|
||||
Bukkit.getLogger().severe("Could not instantiate JDBC driver! " + e.getMessage());
|
||||
}
|
||||
// jdbc:mysql://localhost:3306/Peoples?autoReconnect=true&useSSL=false
|
||||
connectionUrl = "jdbc:mysql://" + dbSettings.getHost() + "/" + dbSettings.getDatabaseName() + "?autoReconnect=true&useSSL=false&allowMultiQueries=true";
|
||||
connectionUrl = "jdbc:mysql://" + dbSettings.getHost() + ":" + dbSettings.getPort() + "/" + dbSettings.getDatabaseName() + "?autoReconnect=true&useSSL=false&allowMultiQueries=true";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,7 +69,17 @@ public class MySQLDatabaseConnecter implements DatabaseConnecter {
|
||||
public void saveYamlFile(YamlConfiguration yamlConfig, String tableName, String fileName,
|
||||
Map<String, String> commentMap) {
|
||||
// Not used
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
Bukkit.getLogger().severe("Could not close MySQL database connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
* Connection to the database
|
||||
*/
|
||||
private Connection connection = null;
|
||||
|
||||
|
||||
private BSkyBlock bskyblock;
|
||||
|
||||
/**
|
||||
@ -53,11 +53,11 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
public MySQLDatabaseHandler(BSkyBlock plugin, Class<T> type, DatabaseConnecter databaseConnecter) {
|
||||
super(plugin, type, databaseConnecter);
|
||||
this.bskyblock = plugin;
|
||||
connection = databaseConnecter.createConnection();
|
||||
connection = (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
|
||||
*/
|
||||
@ -73,7 +73,7 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
plugin.getLogger().severe(() -> "Problem trying to create schema for data object " + dataObject.getCanonicalName() + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Gets the GSON builder
|
||||
private Gson getGSON() {
|
||||
// excludeFieldsWithoutExposeAnnotation - this means that every field to be stored should use @Expose
|
||||
@ -201,4 +201,15 @@ public class MySQLDatabaseHandler<T> extends AbstractDatabaseHandler<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().severe("Could not close database for some reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -642,6 +642,7 @@ public class IslandsManager {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe(()->"Could not load islands to cache! " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@ -815,6 +816,7 @@ public class IslandsManager {
|
||||
public void shutdown(){
|
||||
save(false);
|
||||
islandCache.clear();
|
||||
handler.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import us.tastybento.bskyblock.database.objects.Players;
|
||||
|
||||
public class PlayersManager{
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG = true;
|
||||
private BSkyBlock plugin;
|
||||
private BSBDatabase database;
|
||||
private AbstractDatabaseHandler<Players> handler;
|
||||
@ -106,6 +106,7 @@ public class PlayersManager{
|
||||
public void shutdown(){
|
||||
save(false);
|
||||
playerCache.clear();
|
||||
handler.close();
|
||||
}
|
||||
|
||||
public Players getPlayer(UUID uuid){
|
||||
|
Loading…
Reference in New Issue
Block a user