5.4: Java 16 support, remove H2 (#1932)

* Stop downloading dependencies at startup, include them instead
* 5.4: Removed H2
* Platform Abstraction Layer 5.0.0, delete dependency downloading
* Removed some unnecessary native sqlite drivers
* Serve jquery via CDN

Affects issues:
- Fixes #1886
- Close #1908 (No longer relevant, library no longer included)
This commit is contained in:
Risto Lahtela 2021-06-12 10:21:38 +03:00 committed by GitHub
parent fa4a2e6595
commit e90606b68a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 67 additions and 19450 deletions

View File

@ -4,7 +4,7 @@ dependencies {
compileOnly "com.google.code.gson:gson:$gsonVersion"
}
ext.apiVersion = '5.3-R0.1'
ext.apiVersion = '5.4-R0.1'
publishing {
repositories {

View File

@ -48,7 +48,7 @@ public interface QueryService {
/**
* Get what kind of database is in use.
*
* @return H2, SQLITE or MYSQL
* @return SQLITE or MYSQL
* @throws IllegalStateException If database has not been initialized (Plugin failed to enable)
*/
String getDBType();

View File

@ -33,10 +33,10 @@ allprojects {
wrapper.gradleVersion = "7.0.2"
group "com.djrapitops"
version "5.3-SNAPSHOT"
version "5.4-SNAPSHOT"
ext.majorVersion = '5'
ext.minorVersion = '3'
ext.minorVersion = '4'
ext.buildVersion = buildVersion
ext.fullVersion = project.ext.majorVersion + '.' + project.ext.minorVersion + ' build ' + project.ext.buildVersion
@ -65,11 +65,11 @@ subprojects {
daggerVersion = "2.37"
daggerCompilerVersion = "2.37"
palVersion = "4.1.0"
palVersion = "5.0.0"
bukkitVersion = "1.13.2-R0.1-SNAPSHOT"
spigotVersion = "1.13.2-R0.1-SNAPSHOT"
paperVersion = "1.16.5-R0.1-SNAPSHOT"
paperVersion = "1.13.2-R0.1-SNAPSHOT"
spongeVersion = "7.3.0"
nukkitVersion = "1.0-SNAPSHOT"
bungeeVersion = "1.16-R0.4"
@ -79,14 +79,12 @@ subprojects {
commonsTextVersion = "1.9"
commonsCompressVersion = "1.20"
caffeineVersion = "2.8.0"
h2Version = "1.4.199"
mysqlVersion = "8.0.25"
sqliteVersion = "3.34.0"
hikariVersion = "4.0.3"
slf4jVersion = "1.7.30"
geoIpVersion = "2.15.0"
gsonVersion = "2.8.7"
guavaVersion = "28.0-jre"
bstatsVersion = "2.2.1"
placeholderapiVersion = "2.10.9"
nkPlaceholderapiVersion = "1.4-SNAPSHOT"
@ -120,9 +118,8 @@ subprojects {
testImplementation "com.jayway.awaitility:awaitility:1.7.0" // Awaitility (Concurrent wait conditions)
// Testing dependencies required by Plan
testImplementation "org.xerial:sqlite-jdbc:$sqliteVersion" // SQLite
testImplementation "org.xerial:sqlite-jdbc:$sqliteVersion" // SQLite
testImplementation "mysql:mysql-connector-java:$mysqlVersion" // MySQL
testImplementation "com.h2database:h2:$h2Version" // H2
}
configurations {

View File

@ -29,13 +29,11 @@ import net.playeranalytics.plugin.BukkitPlatformLayer;
import net.playeranalytics.plugin.PlatformAbstractionLayer;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.server.PluginLogger;
import org.apache.maven.model.building.ModelBuildingException;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@ -63,12 +61,6 @@ public class Plan extends JavaPlugin implements PlanPlugin {
abstractionLayer = new BukkitPlatformLayer(this);
pluginLogger = abstractionLayer.getPluginLogger();
runnableFactory = abstractionLayer.getRunnableFactory();
try {
new DependencyStartup(pluginLogger, abstractionLayer.getDependencyLoader()).loadDependencies();
} catch (IOException | ModelBuildingException e) {
getLogger().log(Level.SEVERE, e, () -> this.getClass().getSimpleName());
}
}
@Override

View File

@ -39,15 +39,13 @@ public class BukkitDBSystem extends DBSystem {
Locale locale,
MySQLDB mySQLDB,
SQLiteDB.Factory sqLiteDB,
H2DB.Factory h2DB,
PlanConfig config,
PluginLogger logger
) {
super(locale, sqLiteDB, h2DB, logger);
super(locale, sqLiteDB, logger);
this.config = config;
databases.add(mySQLDB);
databases.add(h2DB.usingDefaultFile());
databases.add(sqLiteDB.usingDefaultFile());
}

View File

@ -28,9 +28,7 @@ import net.playeranalytics.plugin.BungeePlatformLayer;
import net.playeranalytics.plugin.PlatformAbstractionLayer;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.server.PluginLogger;
import org.apache.maven.model.building.ModelBuildingException;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -54,12 +52,6 @@ public class PlanBungee extends Plugin implements PlanPlugin {
abstractionLayer = new BungeePlatformLayer(this);
logger = abstractionLayer.getPluginLogger();
runnableFactory = abstractionLayer.getRunnableFactory();
try {
new DependencyStartup(logger, abstractionLayer.getDependencyLoader()).loadDependencies();
} catch (IOException | ModelBuildingException e) {
getLogger().log(Level.SEVERE, e, () -> this.getClass().getSimpleName());
}
}
@Override

View File

@ -6,9 +6,8 @@ dependencies {
implementation "org.apache.commons:commons-text:$commonsTextVersion"
implementation "org.apache.commons:commons-compress:$commonsCompressVersion"
implementation "com.github.ben-manes.caffeine:caffeine:$caffeineVersion"
compileOnly "com.h2database:h2:$h2Version"
compileOnly "mysql:mysql-connector-java:$mysqlVersion"
compileOnly "org.xerial:sqlite-jdbc:$sqliteVersion"
implementation "mysql:mysql-connector-java:$mysqlVersion"
implementation "org.xerial:sqlite-jdbc:$sqliteVersion"
implementation "com.zaxxer:HikariCP:$hikariVersion"
implementation "org.slf4j:slf4j-nop:$slf4jVersion"
implementation "org.slf4j:slf4j-api:$slf4jVersion"
@ -48,12 +47,18 @@ shadowJar {
exclude 'org/apache/http/**/*' // Unnecessary http client depended on by geolite2 implementation
exclude 'mozilla/**/*'
// Exclude unnecessary SQLite drivers
exclude '**/Linux/android-arm/libsqlitejdbc.so'
exclude '**/DragonFlyBSD/**/libsqlitejdbc.so'
exclude '**/sqlite/jdbc3/*'
relocate 'com.google.protobuf', 'plan.com.mysql.cj.x.google.protobuf'
relocate 'com.maxmind', 'plan.com.maxmind'
relocate 'com.fasterxml', 'plan.com.fasterxml'
relocate 'com.zaxxer', 'plan.com.zaxxer'
relocate 'com.google.gson', 'plan.com.google.gson'
relocate 'com.google.errorprone', 'plan.com.google.errorprone'
relocate 'org.h2', 'plan.org.h2'
relocate 'org.bstats', 'plan.org.bstats'
relocate 'org.slf4j', 'plan.org.slf4j'

View File

@ -1,70 +0,0 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan;
import com.djrapitops.plan.utilities.java.Lists;
import net.playeranalytics.plugin.dependencies.DependencyLoader;
import net.playeranalytics.plugin.me.lucko.jarrelocator.Relocation;
import net.playeranalytics.plugin.server.PluginLogger;
import org.apache.maven.model.building.ModelBuildingException;
import java.io.IOException;
import java.util.Collections;
public class DependencyStartup {
private static final String REPOSITORY_MAVEN_CENTRAL = "https://repo1.maven.org/maven2/";
private final PluginLogger logger;
private final DependencyLoader dependencyLoader;
public DependencyStartup(PluginLogger logger, DependencyLoader dependencyLoader) {
this.logger = logger;
this.dependencyLoader = dependencyLoader;
}
public void loadDependencies() throws IOException, ModelBuildingException {
logger.info("Resolving runtime dependencies..");
dependencyLoader.addDependency(REPOSITORY_MAVEN_CENTRAL,
"com.h2database", "h2", "1.4.199",
Lists.builder(Relocation.class)
.add(new Relocation(
new String(new char[]{'o', 'r', 'g', '.', 'h', '2'}),
"plan.org.h2"
)).build()
);
dependencyLoader.addDependency(REPOSITORY_MAVEN_CENTRAL,
"mysql", "mysql-connector-java", "8.0.23",
Lists.builder(Relocation.class)
.add(new Relocation(
new String(new char[]{'c', 'o', 'm', '.', 'm', 'y', 's', 'q', 'l'}),
"plan.com.mysql"
)).build()
);
dependencyLoader.addDependency(REPOSITORY_MAVEN_CENTRAL,
"org.xerial", "sqlite-jdbc", "3.34.0",
Collections.emptyList()
// Lists.builder(Relocation.class)
// .add(new Relocation(
// new String(new char[]{'o', 'r', 'g', '.', 's', 'q', 'l', 'i', 't', 'e'}),
// "plan.org.sqlite"
// )).build()
);
logger.info("Loading runtime dependencies..");
dependencyLoader.load();
}
}

View File

@ -53,7 +53,7 @@ public class PlanCommand {
private final ImportSystem importSystem;
private final ErrorLogger errorLogger;
private final String DB_ARG_OPTIONS = "MySQL/SQlite/H2";
private final String DB_ARG_OPTIONS = "MySQL/SQLite";
@Inject
public PlanCommand(

View File

@ -209,10 +209,10 @@ public class DatabaseCommands {
public void onMove(String mainCommand, CMDSender sender, Arguments arguments) {
DBType fromDB = arguments.get(0).flatMap(DBType::getForName)
.orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("<MySQL/SQLite/H2>"))));
.orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("<MySQL/SQLite>"))));
DBType toDB = arguments.get(1).flatMap(DBType::getForName)
.orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("<MySQL/SQLite/H2>"))));
.orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("<MySQL/SQLite>"))));
if (fromDB == toDB) {
throw new IllegalArgumentException(locale.getString(CommandLang.FAIL_SAME_DB));
@ -272,7 +272,7 @@ public class DatabaseCommands {
public void onClear(String mainCommand, CMDSender sender, Arguments arguments) {
DBType fromDB = arguments.get(0).flatMap(DBType::getForName)
.orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("<MySQL/SQLite/H2>"))));
.orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("<MySQL/SQLite>"))));
if (sender.supportsChatEvents()) {
sender.buildMessage()
@ -401,7 +401,7 @@ public class DatabaseCommands {
public void onHotswap(CMDSender sender, Arguments arguments) {
DBType toDB = arguments.get(0).flatMap(DBType::getForName)
.orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("<MySQL/SQLite/H2>"))));
.orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("<MySQL/SQLite>"))));
try {
Database database = dbSystem.getActiveDatabaseByType(toDB);

View File

@ -177,7 +177,6 @@ public class NetworkPageExporter extends FileExporter {
"./img/Flaticon_circle.png",
"./css/sb-admin-2.css",
"./css/style.css",
"./vendor/jquery/jquery.min.js",
"./vendor/bootstrap/js/bootstrap.bundle.min.js",
"./vendor/datatables/datatables.min.js",
"./vendor/datatables/datatables.min.css",

View File

@ -143,7 +143,6 @@ public class PlayerPageExporter extends FileExporter {
"../img/Flaticon_circle.png",
"../css/sb-admin-2.css",
"../css/style.css",
"../vendor/jquery/jquery.min.js",
"../vendor/bootstrap/js/bootstrap.bundle.min.js",
"../vendor/datatables/datatables.min.js",
"../vendor/datatables/datatables.min.css",

View File

@ -136,7 +136,6 @@ public class PlayersPageExporter extends FileExporter {
"img/Flaticon_circle.png",
"css/sb-admin-2.css",
"css/style.css",
"vendor/jquery/jquery.min.js",
"vendor/bootstrap/js/bootstrap.bundle.min.js",
"vendor/datatables/datatables.min.js",
"vendor/datatables/datatables.min.css",

View File

@ -201,7 +201,6 @@ public class ServerPageExporter extends FileExporter {
"../img/Flaticon_circle.png",
"../css/sb-admin-2.css",
"../css/style.css",
"../vendor/jquery/jquery.min.js",
"../vendor/bootstrap/js/bootstrap.bundle.min.js",
"../vendor/datatables/datatables.min.js",
"../vendor/datatables/datatables.min.css",

View File

@ -63,15 +63,6 @@ public class DBOpException extends IllegalStateException implements ExceptionWit
case 1054: // MySQL
case 1064:
case 1146:
case 42000: // H2
case 42001:
case 42101:
case 42102:
case 42111:
case 42112:
case 42121:
case 42122:
case 42132:
context.related("SQL Grammar error")
.whatToDo("Report this, there is an SQL grammar error.");
break;
@ -110,17 +101,6 @@ public class DBOpException extends IllegalStateException implements ExceptionWit
case 1364:
case 1451:
case 1557:
case 22001: // H2
case 22003:
case 22012:
case 22018:
case 22025:
case 23000:
case 23002:
case 23502:
case 23506:
case 23507:
case 23513:
context.related("Constraint Violation")
.whatToDo("Report this, there is an SQL Constraint Violation.");
break;

View File

@ -22,7 +22,6 @@ import dagger.Module;
import dagger.Provides;
import net.playeranalytics.plugin.PlatformAbstractionLayer;
import net.playeranalytics.plugin.PluginInformation;
import net.playeranalytics.plugin.dependencies.DependencyLoader;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.server.Listeners;
import net.playeranalytics.plugin.server.PluginLogger;
@ -63,12 +62,6 @@ public class PlatformAbstractionLayerModule {
return abstractionLayer.getRunnableFactory();
}
@Provides
@Singleton
DependencyLoader provideDependencyLoader(PlatformAbstractionLayer abstractionLayer) {
return abstractionLayer.getDependencyLoader();
}
@Provides
@Singleton
Listeners provideListeners(PlatformAbstractionLayer abstractionLayer) {

View File

@ -29,7 +29,6 @@ import com.djrapitops.plan.storage.database.queries.containers.PlayerContainerQu
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries;
import com.djrapitops.plan.storage.database.queries.schema.H2SchemaQueries;
import com.djrapitops.plan.storage.database.queries.schema.MySQLSchemaQueries;
import com.djrapitops.plan.storage.database.queries.schema.SQLiteSchemaQueries;
@ -88,8 +87,6 @@ public class CommonQueriesImplementation implements CommonQueries {
public boolean doesDBHaveTable(String table) {
DBType dbType = db.getType();
switch (dbType) {
case H2:
return db.query(H2SchemaQueries.doesTableExist(table));
case SQLITE:
return db.query(SQLiteSchemaQueries.doesTableExist(table));
case MYSQL:
@ -103,8 +100,6 @@ public class CommonQueriesImplementation implements CommonQueries {
public boolean doesDBHaveTableColumn(String table, String column) {
DBType dbType = db.getType();
switch (dbType) {
case H2:
return db.query(H2SchemaQueries.doesColumnExist(table, column));
case MYSQL:
return db.query(MySQLSchemaQueries.doesColumnExist(table, column));
case SQLITE:

View File

@ -143,7 +143,11 @@ public class ConfigUpdater {
new ConfigChange.BooleanToString("Time.Use_server_timezone", FormatSettings.TIMEZONE.getPath(), "server", "UTC"),
new ConfigChange.Removed("Plugin.Logging.Debug"),
new ConfigChange.Moved("Plugins.PlaceholderAPI.Placeholders", "Plugins.PlaceholderAPI.Tracked_player_placeholders")
new ConfigChange.Moved("Plugins.PlaceholderAPI.Placeholders", "Plugins.PlaceholderAPI.Tracked_player_placeholders"),
new ConfigChange.Removed("Database.H2.User"),
new ConfigChange.Removed("Database.H2.Password"),
new ConfigChange.Removed("Database.H2"),
};
}

View File

@ -33,8 +33,6 @@ public class DatabaseSettings {
public static final Setting<String> MYSQL_HOST = new StringSetting("Database.MySQL.Host");
public static final Setting<String> MYSQL_PORT = new StringSetting("Database.MySQL.Port", NumberUtils::isParsable);
public static final Setting<String> MYSQL_USER = new StringSetting("Database.MySQL.User");
public static final Setting<String> H2_USER = new StringSetting("Database.H2.User");
public static final Setting<String> H2_PASS = new StringSetting("Database.H2.Password");
public static final Setting<String> MYSQL_PASS = new StringSetting("Database.MySQL.Password");
public static final Setting<String> MYSQL_DATABASE = new StringSetting("Database.MySQL.Database");
public static final Setting<String> MYSQL_LAUNCH_OPTIONS = new StringSetting("Database.MySQL.Launch_options");

View File

@ -37,7 +37,6 @@ public class DBSystem implements SubSystem {
protected final Locale locale;
private final SQLiteDB.Factory sqLiteFactory;
private final H2DB.Factory h2Factory;
protected final PluginLogger logger;
protected Database db;
@ -46,17 +45,18 @@ public class DBSystem implements SubSystem {
public DBSystem(
Locale locale,
SQLiteDB.Factory sqLiteDB,
H2DB.Factory h2Factory,
PluginLogger logger
) {
this.locale = locale;
this.sqLiteFactory = sqLiteDB;
this.h2Factory = h2Factory;
this.logger = logger;
databases = new HashSet<>();
}
public Database getActiveDatabaseByName(String dbName) {
if ("h2".equalsIgnoreCase(dbName)) {
throw new EnableException("H2 database is NO LONGER SUPPORTED. Downgrade to 5.3 build 1284 and migrate to SQLite or MySQL using '/plan db move h2 <db>' command");
}
return DBType.getForName(dbName)
.map(this::getActiveDatabaseByType)
.orElseThrow(() -> new IllegalArgumentException(locale.getString(PluginLang.ENABLE_FAIL_WRONG_DB, dbName)));
@ -107,7 +107,4 @@ public class DBSystem implements SubSystem {
return sqLiteFactory;
}
public H2DB.Factory getH2Factory() {
return h2Factory;
}
}

View File

@ -30,8 +30,7 @@ import java.util.Optional;
public enum DBType {
MYSQL("MySQL", true, new Sql.MySQL()),
SQLITE("SQLite", false, new Sql.SQLite()),
H2("H2", true, new Sql.H2());
SQLITE("SQLite", false, new Sql.SQLite());
private final String name;
private final String configName;

View File

@ -1,214 +0,0 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.storage.database;
import com.djrapitops.plan.exceptions.database.DBInitException;
import com.djrapitops.plan.identification.ServerInfo;
import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.DatabaseSettings;
import com.djrapitops.plan.settings.locale.Locale;
import com.djrapitops.plan.storage.file.PlanFiles;
import com.djrapitops.plan.storage.upkeep.DBKeepAliveTask;
import com.djrapitops.plan.utilities.MiscUtils;
import com.djrapitops.plan.utilities.logging.ErrorLogger;
import dagger.Lazy;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.scheduling.Task;
import net.playeranalytics.plugin.server.PluginLogger;
import org.h2.jdbcx.JdbcDataSource;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;
/**
* Implementation of the H2 database
*
* @author Fuzzlemann
*/
public class H2DB extends SQLDB {
private final File databaseFile;
private final String dbName;
private Connection connection;
private Task connectionPingTask;
private H2DB(
File databaseFile,
Locale locale,
PlanConfig config,
Lazy<ServerInfo> serverInfo,
RunnableFactory runnableFactory,
PluginLogger logger,
ErrorLogger errorLogger
) {
super(() -> serverInfo.get().getServerUUID(), locale, config, runnableFactory, logger, errorLogger);
dbName = databaseFile.getName();
this.databaseFile = databaseFile;
}
@Override
public void setupDataSource() {
try {
connection = getNewConnection(databaseFile);
} catch (SQLException e) {
throw new DBInitException(e.getMessage(), e);
}
startConnectionPingTask();
}
public Connection getNewConnection(File dbFile) throws SQLException {
String dbFilePath = dbFile.getAbsolutePath();
Connection newConnection = getConnectionFor(dbFilePath);
newConnection.setAutoCommit(false);
return newConnection;
}
private Connection getConnectionFor(String dbFilePath) throws SQLException {
String username = config.get(DatabaseSettings.H2_USER);
String password = config.get(DatabaseSettings.H2_PASS);
JdbcDataSource jdbcDataSource = new JdbcDataSource();
jdbcDataSource.setURL("jdbc:h2:file:" + dbFilePath + ";mode=MySQL;DATABASE_TO_UPPER=false");
jdbcDataSource.setUser(username);
jdbcDataSource.setPassword(password);
return jdbcDataSource.getConnection();
}
private void startConnectionPingTask() {
stopConnectionPingTask();
logger.warn("! ! ! ---------- ! ! !");
logger.warn("H2 database is DEPRECATED and WILL STOP WORKING in version 5.4 - It is recommended to move to MySQL or SQLite when possible.");
logger.warn("See https://github.com/plan-player-analytics/Plan/issues/1472 for details");
logger.warn("! ! ! ---------- ! ! !");
try {
// Maintains Connection.
connectionPingTask = runnableFactory.create(
new DBKeepAliveTask(connection, () -> getNewConnection(databaseFile), logger, errorLogger)
).runTaskTimerAsynchronously(60L * 20L, 60L * 20L);
} catch (Exception ignored) {
// Task failed to register because plugin is being disabled
}
}
private void stopConnectionPingTask() {
if (connectionPingTask != null) {
try {
connectionPingTask.cancel();
} catch (Exception ignored) {
// Sometimes task systems fail to cancel a task,
// usually this is called on disable, so no need for users to report this.
}
}
}
@Override
public DBType getType() {
return DBType.H2;
}
@Override
public Connection getConnection() throws SQLException {
if (connection == null) {
connection = getNewConnection(databaseFile);
}
return connection;
}
@Override
public void close() {
super.close();
stopConnectionPingTask();
if (connection != null) {
MiscUtils.close(connection);
}
}
@Override
public void returnToPool(Connection connection) {
// Connection pool not in use, no action required.
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
H2DB h2DB = (H2DB) o;
return Objects.equals(dbName, h2DB.dbName);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), dbName);
}
@Singleton
public static class Factory {
private final Locale locale;
private final PlanConfig config;
private final Lazy<ServerInfo> serverInfo;
private final RunnableFactory runnableFactory;
private final PluginLogger logger;
private final ErrorLogger errorLogger1;
private final PlanFiles files;
@Inject
public Factory(
Locale locale,
PlanConfig config,
PlanFiles files,
Lazy<ServerInfo> serverInfo,
RunnableFactory runnableFactory,
PluginLogger logger,
ErrorLogger errorLogger1
) {
this.locale = locale;
this.config = config;
this.files = files;
this.serverInfo = serverInfo;
this.runnableFactory = runnableFactory;
this.logger = logger;
this.errorLogger1 = errorLogger1;
}
public H2DB usingDefaultFile() {
return usingFileCalled("h2database");
}
public H2DB usingFileCalled(String fileName) {
return usingFile(files.getFileFromPluginFolder(fileName));
}
public H2DB usingFile(File databaseFile) {
return new H2DB(databaseFile,
locale, config, serverInfo,
runnableFactory, logger, errorLogger1
);
}
}
}

View File

@ -35,10 +35,9 @@ public class ProxyDBSystem extends DBSystem {
Locale locale,
MySQLDB mySQLDB,
SQLiteDB.Factory sqLiteDB,
H2DB.Factory h2DB,
PluginLogger logger
) {
super(locale, sqLiteDB, h2DB, logger);
super(locale, sqLiteDB, logger);
databases.add(mySQLDB);
db = mySQLDB;
}

View File

@ -150,7 +150,7 @@ public class UserIdentifierQueries {
* Query database for a Player name matching a specific player's UUID.
*
* @param playerUUID UUID of the Player
* @return Optional: name if found, empty if not - Case is stored unless using a H2 database.
* @return Optional: name if found, empty if not.
*/
public static Query<Optional<String>> fetchPlayerNameOf(UUID playerUUID) {
String sql = Select.from(UsersTable.TABLE_NAME, UsersTable.USER_NAME).where(UsersTable.USER_UUID + "=?").toString();

View File

@ -1,80 +0,0 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.storage.database.queries.schema;
import com.djrapitops.plan.storage.database.queries.HasMoreThanZeroQueryStatement;
import com.djrapitops.plan.storage.database.queries.Query;
import com.djrapitops.plan.storage.database.queries.QueryStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
/**
* Static method class for H2 Schema related queries.
*
* @author AuroraLS3
*/
public class H2SchemaQueries {
private H2SchemaQueries() {
/* Static method class */
}
public static Query<Boolean> doesTableExist(String tableName) {
String sql = SELECT + "COUNT(1) as c FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?";
return new HasMoreThanZeroQueryStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, tableName);
}
};
}
public static Query<Boolean> doesColumnExist(String tableName, String columnName) {
String sql = SELECT + "COUNT(1) as c FROM INFORMATION_SCHEMA.COLUMNS" +
" WHERE TABLE_NAME=? AND COLUMN_NAME=?";
return new HasMoreThanZeroQueryStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, tableName);
statement.setString(2, columnName);
}
};
}
public static Query<Integer> columnVarcharLength(String table, String column) {
String sql = SELECT + "CHARACTER_MAXIMUM_LENGTH" +
FROM + "INFORMATION_SCHEMA.COLUMNS " +
WHERE + "TABLE_NAME=? AND COLUMN_NAME=?";
return new QueryStatement<Integer>(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, table);
statement.setString(2, column);
}
@Override
public Integer processResults(ResultSet set) throws SQLException {
return set.next() ? set.getInt("CHARACTER_MAXIMUM_LENGTH") : Integer.MAX_VALUE;
}
};
}
}

View File

@ -130,35 +130,6 @@ public abstract class Sql {
}
}
// https://h2database.com/html/functions.html
public static class H2 extends MySQL {
@Override
public String epochSecondToDate(String sql) {
return "DATEADD('SECOND', " + sql + ", DATE '1970-01-01')";
}
@Override
public String dateToEpochSecond(String sql) {
return "DATEDIFF('SECOND', DATE '1970-01-01', " + sql + ')';
}
@Override
public String dateToDayOfWeek(String sql) {
return "DAY_OF_WEEK(" + sql + ')';
}
@Override
public String dateToHourStamp(String sql) {
return "DATE_FORMAT(" + sql + ",'yyyy-MM-dd HH:00:00')";
}
@Override
public String dateToHour(String sql) {
return "HOUR(" + sql + ')';
}
}
// https://sqlite.org/lang_datefunc.html
public static class SQLite extends Sql {

View File

@ -97,9 +97,7 @@ public abstract class Transaction {
// Retry if deadlock occurs.
int errorCode = statementFail.getErrorCode();
boolean mySQLDeadlock = dbType == DBType.MYSQL && errorCode == 1213;
boolean h2Deadlock = dbType == DBType.H2 && errorCode == 40001;
boolean deadlocked = mySQLDeadlock || h2Deadlock
|| statementFail instanceof SQLTransactionRollbackException;
boolean deadlocked = mySQLDeadlock || statementFail instanceof SQLTransactionRollbackException;
if (deadlocked && attempts < ATTEMPT_LIMIT) {
executeTransaction(db); // Recurse to attempt again.
return;

View File

@ -17,7 +17,6 @@
package com.djrapitops.plan.storage.database.transactions.patches;
import com.djrapitops.plan.storage.database.DBType;
import com.djrapitops.plan.storage.database.queries.schema.H2SchemaQueries;
import com.djrapitops.plan.storage.database.queries.schema.MySQLSchemaQueries;
import com.djrapitops.plan.storage.database.sql.building.Sql;
import com.djrapitops.plan.storage.database.sql.tables.ExtensionPlayerTableValueTable;
@ -46,11 +45,7 @@ public class ExtensionTableRowValueLengthPatch extends Patch {
}
private int columnVarcharLength(String table, String column) {
if (dbType == DBType.MYSQL) {
return query(MySQLSchemaQueries.columnVarcharLength(table, column));
} else {
return query(H2SchemaQueries.columnVarcharLength(table, column));
}
return query(MySQLSchemaQueries.columnVarcharLength(table, column));
}
@Override

View File

@ -19,7 +19,6 @@ package com.djrapitops.plan.storage.database.transactions.patches;
import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.storage.database.DBType;
import com.djrapitops.plan.storage.database.queries.QueryStatement;
import com.djrapitops.plan.storage.database.queries.schema.H2SchemaQueries;
import com.djrapitops.plan.storage.database.queries.schema.MySQLSchemaQueries;
import com.djrapitops.plan.storage.database.queries.schema.SQLiteSchemaQueries;
import com.djrapitops.plan.storage.database.transactions.init.OperationCriticalTransaction;
@ -75,8 +74,6 @@ public abstract class Patch extends OperationCriticalTransaction {
protected boolean hasTable(String tableName) {
switch (dbType) {
case H2:
return query(H2SchemaQueries.doesTableExist(tableName));
case SQLITE:
return query(SQLiteSchemaQueries.doesTableExist(tableName));
case MYSQL:
@ -88,8 +85,6 @@ public abstract class Patch extends OperationCriticalTransaction {
protected boolean hasColumn(String tableName, String columnName) {
switch (dbType) {
case H2:
return query(H2SchemaQueries.doesColumnExist(tableName, columnName));
case MYSQL:
return query(MySQLSchemaQueries.doesColumnExist(tableName, columnName));
case SQLITE:
@ -114,7 +109,6 @@ public abstract class Patch extends OperationCriticalTransaction {
private String getRenameTableSQL(String from, String to) {
switch (dbType) {
case SQLITE:
case H2:
return ALTER_TABLE + from + " RENAME TO " + to;
case MYSQL:
return "RENAME TABLE " + from + " TO " + to;

View File

@ -33,6 +33,7 @@ import java.util.concurrent.TimeUnit;
@Singleton
public class OldDependencyCacheDeletionTask extends TaskSystem.Task {
private final File oldDependencyCache;
private final File dependencyCache;
private final File libraries;
@ -43,7 +44,8 @@ public class OldDependencyCacheDeletionTask extends TaskSystem.Task {
PlanFiles files,
ErrorLogger errorLogger
) {
dependencyCache = files.getDataDirectory().resolve("dependency_cache").toFile();
oldDependencyCache = files.getDataDirectory().resolve("dependency_cache").toFile();
dependencyCache = files.getDataDirectory().resolve("dep_cache").toFile();
libraries = files.getDataDirectory().resolve("libraries").toFile();
this.errorLogger = errorLogger;
}
@ -56,6 +58,7 @@ public class OldDependencyCacheDeletionTask extends TaskSystem.Task {
@Override
public void run() {
tryToDeleteDirectory(oldDependencyCache);
tryToDeleteDirectory(dependencyCache);
tryToDeleteDirectory(libraries);
}

View File

@ -21,7 +21,7 @@ Plugin:
Configuration:
Allow_proxy_to_manage_settings: true
# -----------------------------------------------------
# Supported databases: SQLite, H2, MySQL
# Supported databases: SQLite, MySQL
# -----------------------------------------------------
Database:
Type: SQLite
@ -34,9 +34,6 @@ Database:
# Launch options to append after mysql driver address
Launch_options: "?rewriteBatchedStatements=true&useSSL=false&serverTimezone=UTC"
Max_connections: 8
H2:
User: root
Password: minecraft
# -----------------------------------------------------
# More information about SSL Certificate Settings:
# https://github.com/plan-player-analytics/Plan/wiki/SSL-Certificate-%28HTTPS%29-Set-Up

View File

@ -230,7 +230,9 @@
<!-- End of Page Wrapper -->
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Custom scripts for all pages-->

View File

@ -212,7 +212,9 @@
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Custom scripts for all pages-->

View File

@ -841,7 +841,9 @@
<!-- End of Page Wrapper -->
<!-- Bootstrap core JavaScript-->
<script src="./vendor/jquery/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="./vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Page level plugins -->

View File

@ -688,7 +688,9 @@
<!-- End of Page Wrapper -->
<!-- Bootstrap core JavaScript-->
<script src="../vendor/jquery/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Page level plugins -->

View File

@ -260,7 +260,9 @@
<!-- End of Page Wrapper -->
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Page level plugins -->

View File

@ -309,7 +309,9 @@
<!-- End of Page Wrapper -->
<!-- Bootstrap core JavaScript-->
<script src="./vendor/jquery/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="./vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Page level plugins -->

View File

@ -174,7 +174,9 @@
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Custom scripts for all pages-->

View File

@ -1326,7 +1326,9 @@
<!-- End of Page Wrapper -->
<!-- Bootstrap core JavaScript-->
<script src="../vendor/jquery/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Page level plugins -->

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,133 +0,0 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.storage.database;
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
import com.djrapitops.plan.delivery.domain.keys.PlayerKeys;
import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.DatabaseSettings;
import com.djrapitops.plan.storage.database.queries.containers.ContainerFetchQueries;
import com.djrapitops.plan.storage.database.transactions.Transaction;
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
import com.djrapitops.plan.storage.database.transactions.init.CreateTablesTransaction;
import com.djrapitops.plan.storage.database.transactions.patches.Patch;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import utilities.OptionalAssert;
import utilities.TestConstants;
import utilities.mocks.PluginMockComponent;
import java.nio.file.Path;
/**
* Test for the patching of Plan 4.5.2 H2 DB into the newest schema.
*
* @author AuroraLS3
*/
class DBPatchH2RegressionTest extends DBPatchRegressionTest {
private static PluginMockComponent component;
private final String serverTable = "CREATE TABLE IF NOT EXISTS plan_servers (id integer NOT NULL AUTO_INCREMENT, uuid varchar(36) NOT NULL UNIQUE, name varchar(100), web_address varchar(100), is_installed boolean NOT NULL DEFAULT 1, max_players integer NOT NULL DEFAULT -1, PRIMARY KEY (id))";
private final String usersTable = "CREATE TABLE IF NOT EXISTS plan_users (id integer NOT NULL AUTO_INCREMENT, uuid varchar(36) NOT NULL UNIQUE, registered bigint NOT NULL, name varchar(16) NOT NULL, times_kicked integer NOT NULL DEFAULT 0, PRIMARY KEY (id))";
private final String userInfoTable = "CREATE TABLE IF NOT EXISTS plan_user_info (user_id integer NOT NULL, registered bigint NOT NULL, opped boolean NOT NULL DEFAULT 0, banned boolean NOT NULL DEFAULT 0, server_id integer NOT NULL, FOREIGN KEY(user_id) REFERENCES plan_users(id), FOREIGN KEY(server_id) REFERENCES plan_servers(id))";
private final String geoInfoTable = "CREATE TABLE IF NOT EXISTS plan_ips (user_id integer NOT NULL, ip varchar(39) NOT NULL, geolocation varchar(50) NOT NULL, ip_hash varchar(200), last_used bigint NOT NULL DEFAULT 0, FOREIGN KEY(user_id) REFERENCES plan_users(id))";
private final String nicknameTable = "CREATE TABLE IF NOT EXISTS plan_nicknames (user_id integer NOT NULL, nickname varchar(75) NOT NULL, server_id integer NOT NULL, last_used bigint NOT NULL, FOREIGN KEY(user_id) REFERENCES plan_users(id), FOREIGN KEY(server_id) REFERENCES plan_servers(id))";
private final String sessionsTable = "CREATE TABLE IF NOT EXISTS plan_sessions (id integer NOT NULL AUTO_INCREMENT, user_id integer NOT NULL, server_id integer NOT NULL, session_start bigint NOT NULL, session_end bigint NOT NULL, mob_kills integer NOT NULL, deaths integer NOT NULL, afk_time bigint NOT NULL, FOREIGN KEY(user_id) REFERENCES plan_users(id), FOREIGN KEY(server_id) REFERENCES plan_servers(id), PRIMARY KEY (id))";
private final String killsTable = "CREATE TABLE IF NOT EXISTS plan_kills (killer_id integer NOT NULL, victim_id integer NOT NULL, server_id integer NOT NULL, weapon varchar(30) NOT NULL, date bigint NOT NULL, session_id integer NOT NULL, FOREIGN KEY(killer_id) REFERENCES plan_users(id), FOREIGN KEY(victim_id) REFERENCES plan_users(id), FOREIGN KEY(session_id) REFERENCES plan_sessions(id), FOREIGN KEY(server_id) REFERENCES plan_servers(id))";
private final String pingTable = "CREATE TABLE IF NOT EXISTS plan_ping (id integer NOT NULL AUTO_INCREMENT, user_id integer NOT NULL, server_id integer NOT NULL, date bigint NOT NULL, max_ping integer NOT NULL, min_ping integer NOT NULL, avg_ping double NOT NULL, PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES plan_users(id), FOREIGN KEY(server_id) REFERENCES plan_servers(id))";
private final String commandUseTable = "CREATE TABLE IF NOT EXISTS plan_commandusages (id integer NOT NULL AUTO_INCREMENT, command varchar(20) NOT NULL, times_used integer NOT NULL, server_id integer NOT NULL, PRIMARY KEY (id), FOREIGN KEY(server_id) REFERENCES plan_servers(id))";
private final String tpsTable = "CREATE TABLE IF NOT EXISTS plan_tps (server_id integer NOT NULL, date bigint NOT NULL, tps double NOT NULL, players_online integer NOT NULL, cpu_usage double NOT NULL, ram_usage bigint NOT NULL, entities integer NOT NULL, chunks_loaded integer NOT NULL, free_disk_space bigint NOT NULL, FOREIGN KEY(server_id) REFERENCES plan_servers(id))";
private final String worldsTable = "CREATE TABLE IF NOT EXISTS plan_worlds (id integer NOT NULL AUTO_INCREMENT, world_name varchar(100) NOT NULL, server_id integer NOT NULL, PRIMARY KEY (id), FOREIGN KEY(server_id) REFERENCES plan_servers(id))";
private final String worldTimesTable = "CREATE TABLE IF NOT EXISTS plan_world_times (user_id integer NOT NULL, world_id integer NOT NULL, server_id integer NOT NULL, session_id integer NOT NULL, survival_time bigint NOT NULL DEFAULT 0, creative_time bigint NOT NULL DEFAULT 0, adventure_time bigint NOT NULL DEFAULT 0, spectator_time bigint NOT NULL DEFAULT 0, FOREIGN KEY(user_id) REFERENCES plan_users(id), FOREIGN KEY(world_id) REFERENCES plan_worlds(id), FOREIGN KEY(server_id) REFERENCES plan_servers(id), FOREIGN KEY(session_id) REFERENCES plan_sessions(id))";
private final String securityTable = "CREATE TABLE IF NOT EXISTS plan_security (username varchar(100) NOT NULL UNIQUE, salted_pass_hash varchar(100) NOT NULL UNIQUE, permission_level integer NOT NULL)";
private final String transferTable = "CREATE TABLE IF NOT EXISTS plan_transfer (sender_server_id integer NOT NULL, expiry_date bigint NOT NULL DEFAULT 0, type varchar(100) NOT NULL, extra_variables varchar(255) DEFAULT '', content_64 MEDIUMTEXT, part bigint NOT NULL DEFAULT 0, FOREIGN KEY(sender_server_id) REFERENCES plan_servers(id))";
private H2DB underTest;
@BeforeAll
static void setUpComponentMock(@TempDir Path tempDir) {
component = new PluginMockComponent(tempDir);
}
@AfterAll
static void closeSystem() throws Exception {
component.getPlanSystem().disable();
}
@BeforeEach
void setUpDBWithOldSchema() throws Exception {
PlanConfig config = component.getPlanSystem().getConfigSystem().getConfig();
config.set(DatabaseSettings.H2_USER, "user");
config.set(DatabaseSettings.H2_PASS, "pass");
underTest = component.getPlanSystem().getDatabaseSystem().getH2Factory()
.usingFileCalled("test");
underTest.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
underTest.init();
// Initialize database with the old table schema
dropAllTables(underTest);
underTest.executeTransaction(new Transaction() {
@Override
protected void performOperations() {
execute(serverTable);
execute(usersTable);
execute(userInfoTable);
execute(geoInfoTable);
execute(nicknameTable);
execute(sessionsTable);
execute(killsTable);
execute(pingTable);
execute(commandUseTable);
execute(tpsTable);
execute(worldsTable);
execute(worldTimesTable);
execute(securityTable);
execute(transferTable);
}
});
underTest.executeTransaction(new CreateTablesTransaction());
insertData(underTest);
}
@AfterEach
void closeDatabase() {
underTest.close();
}
@Test
void h2PatchesAreApplied() {
Patch[] patches = underTest.patches();
for (Patch patch : patches) {
underTest.executeTransaction(patch);
}
assertPatchesHaveBeenApplied(patches);
// Make sure that a fetch works.
PlayerContainer player = underTest.query(ContainerFetchQueries.fetchPlayerContainer(TestConstants.PLAYER_ONE_UUID));
OptionalAssert.equals(1, player.getValue(PlayerKeys.PLAYER_KILL_COUNT));
// Make sure no foreign key checks fail on removal
underTest.executeTransaction(new RemoveEverythingTransaction());
}
}

View File

@ -1,159 +0,0 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.storage.database;
import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.delivery.DeliveryUtilities;
import com.djrapitops.plan.extension.ExtensionSvc;
import com.djrapitops.plan.identification.Server;
import com.djrapitops.plan.identification.ServerInfo;
import com.djrapitops.plan.identification.ServerUUID;
import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.storage.database.queries.*;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
import com.djrapitops.plan.storage.database.transactions.init.CreateTablesTransaction;
import com.djrapitops.plan.storage.database.transactions.patches.Patch;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import utilities.DBPreparer;
import utilities.RandomData;
import utilities.TestErrorLogger;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
/**
* Tests for the H2 database.
*
* @author AuroraLS3
* @see DatabaseTest
* @see ExtensionsDatabaseTest
*/
@ExtendWith(MockitoExtension.class)
public class H2Test implements DatabaseTest,
DatabaseBackupTest,
ExtensionsDatabaseTest,
ActivityIndexQueriesTest,
GeolocationQueriesTest,
NicknameQueriesTest,
PingQueriesTest,
SessionQueriesTest,
ServerQueriesTest,
TPSQueriesTest,
UserInfoQueriesTest,
WebUserQueriesTest {
private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
private static Database database;
private static DatabaseTestComponent component;
private static DBPreparer preparer;
@BeforeAll
static void setupDatabase(@TempDir Path temp) {
component = DaggerDatabaseTestComponent.builder()
.bindTemporaryDirectory(temp)
.build();
preparer = new DBPreparer(component, TEST_PORT_NUMBER);
database = preparer.prepareH2()
.orElseThrow(IllegalStateException::new);
}
@BeforeEach
void setUp() {
TestErrorLogger.throwErrors(true);
db().executeTransaction(new Patch() {
@Override
public boolean hasBeenApplied() {
return false;
}
@Override
public void applyPatch() {
dropTable("plan_world_times");
dropTable("plan_kills");
dropTable("plan_sessions");
dropTable("plan_worlds");
dropTable("plan_users");
}
});
db().executeTransaction(new CreateTablesTransaction());
db().executeTransaction(new RemoveEverythingTransaction());
db().executeTransaction(new StoreServerInformationTransaction(new Server(serverUUID(), "ServerName", "")));
assertEquals(serverUUID(), ((SQLDB) db()).getServerUUIDSupplier().get());
}
@AfterAll
static void disableSystem() {
if (database != null) {
database.close();
System.out.println("Database state after close: " + database.getState().name());
}
preparer.tearDown();
}
@Override
public Database db() {
return database;
}
@Override
public ServerUUID serverUUID() {
return component.serverInfo().getServerUUID();
}
@Override
public PlanConfig config() {
return component.config();
}
@Override
public DBSystem dbSystem() {
return component.dbSystem();
}
@Override
public ServerInfo serverInfo() {
return component.serverInfo();
}
@Override
public DeliveryUtilities deliveryUtilities() {
return component.deliveryUtilities();
}
@Override
public ExtensionSvc extensionService() {
return component.extensionService();
}
@Override
public PlanSystem system() {
PlanSystem mockSystem = Mockito.mock(PlanSystem.class);
when(mockSystem.getPlanFiles()).thenReturn(component.files());
return mockSystem;
}
}

View File

@ -23,7 +23,6 @@ import com.djrapitops.plan.gathering.domain.GeoInfo;
import com.djrapitops.plan.gathering.domain.TPS;
import com.djrapitops.plan.storage.database.Database;
import com.djrapitops.plan.storage.database.DatabaseTestPreparer;
import com.djrapitops.plan.storage.database.H2DB;
import com.djrapitops.plan.storage.database.SQLiteDB;
import com.djrapitops.plan.storage.database.queries.objects.*;
import com.djrapitops.plan.storage.database.transactions.BackupCopyTransaction;
@ -102,33 +101,6 @@ public interface DatabaseBackupTest extends DatabaseTestPreparer {
}
}
@Test
default void testBackupAndRestoreH2() throws Exception {
File tempFile = Files.createTempFile(system().getPlanFiles().getDataFolder().toPath(), "backup-", ".db").toFile();
tempFile.deleteOnExit();
H2DB backup = dbSystem().getH2Factory().usingFile(tempFile);
backup.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
try {
backup.init();
saveDataForBackup();
backup.executeTransaction(new BackupCopyTransaction(db(), backup));
assertQueryResultIsEqual(db(), backup, BaseUserQueries.fetchAllBaseUsers());
assertQueryResultIsEqual(db(), backup, UserInfoQueries.fetchAllUserInformation());
assertQueryResultIsEqual(db(), backup, NicknameQueries.fetchAllNicknameData());
assertQueryResultIsEqual(db(), backup, GeoInfoQueries.fetchAllGeoInformation());
assertQueryResultIsEqual(db(), backup, SessionQueries.fetchAllSessions());
assertQueryResultIsEqual(db(), backup, LargeFetchQueries.fetchAllWorldNames());
assertQueryResultIsEqual(db(), backup, LargeFetchQueries.fetchAllTPSData());
assertQueryResultIsEqual(db(), backup, ServerQueries.fetchPlanServerInformation());
assertQueryResultIsEqual(db(), backup, WebUserQueries.fetchAllUsers());
} finally {
backup.close();
}
}
default <T> void assertQueryResultIsEqual(Database one, Database two, Query<T> query) {
assertEquals(one.query(query), two.query(query));
}

View File

@ -49,11 +49,6 @@ public class DBPreparer {
return Optional.of(prepareDBByName(dbName));
}
public Optional<Database> prepareH2() {
String dbName = DBType.H2.getName();
return Optional.of(prepareDBByName(dbName));
}
private SQLDB prepareDBByName(String dbName) {
PlanConfig config = dependencies.config();
config.set(WebserverSettings.PORT, testPortNumber);

View File

@ -88,8 +88,6 @@ public class TestSettings {
settings.remove(PluginSettings.PROXY_COPY_CONFIG);
settings.remove(DatabaseSettings.TYPE);
settings.remove(DisplaySettings.WORLD_ALIASES);
settings.remove(DatabaseSettings.H2_USER);
settings.remove(DatabaseSettings.H2_PASS);
return settings;
}
}

View File

@ -21,7 +21,6 @@ import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.DatabaseSettings;
import com.djrapitops.plan.settings.locale.Locale;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.H2DB;
import com.djrapitops.plan.storage.database.MySQLDB;
import com.djrapitops.plan.storage.database.SQLiteDB;
import dagger.Module;
@ -38,15 +37,13 @@ public class DBSystemModule {
PlanConfig config,
Locale locale,
SQLiteDB.Factory sqLiteDB,
H2DB.Factory h2Factory,
MySQLDB mySQLDB,
PluginLogger logger
) {
return new DBSystem(locale, sqLiteDB, h2Factory, logger) {
return new DBSystem(locale, sqLiteDB, logger) {
@Override
public void enable() throws EnableException {
databases.add(sqLiteDB.usingDefaultFile());
databases.add(h2Factory.usingDefaultFile());
databases.add(mySQLDB);
String dbType = config.get(DatabaseSettings.TYPE).toLowerCase().trim();
db = getActiveDatabaseByName(dbType);

View File

@ -19,7 +19,6 @@ package utilities.mocks;
import com.djrapitops.plan.PlanPlugin;
import net.playeranalytics.plugin.PlatformAbstractionLayer;
import net.playeranalytics.plugin.PluginInformation;
import net.playeranalytics.plugin.dependencies.DependencyLoader;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.server.Listeners;
import net.playeranalytics.plugin.server.PluginLogger;
@ -31,7 +30,6 @@ import utilities.mocks.objects.TestRunnableFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLClassLoader;
import java.nio.file.Files;
public class TestPlatformAbstractionLayer implements PlatformAbstractionLayer {
@ -96,9 +94,4 @@ public class TestPlatformAbstractionLayer implements PlatformAbstractionLayer {
}
};
}
@Override
public DependencyLoader getDependencyLoader() {
return new DependencyLoader((URLClassLoader) getClass().getClassLoader(), getPluginInformation());
}
}

View File

@ -33,9 +33,7 @@ import net.playeranalytics.plugin.NukkitPlatformLayer;
import net.playeranalytics.plugin.PlatformAbstractionLayer;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.server.PluginLogger;
import org.apache.maven.model.building.ModelBuildingException;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -68,12 +66,6 @@ public class PlanNukkit extends PluginBase implements PlanPlugin {
abstractionLayer = new NukkitPlatformLayer(this);
logger = abstractionLayer.getPluginLogger();
runnableFactory = abstractionLayer.getRunnableFactory();
try {
new DependencyStartup(logger, abstractionLayer.getDependencyLoader()).loadDependencies();
} catch (IOException | ModelBuildingException e) {
Logger.getGlobal().log(Level.SEVERE, e, () -> this.getClass().getSimpleName());
}
}
@Override

View File

@ -39,15 +39,13 @@ public class NukkitDBSystem extends DBSystem {
Locale locale,
MySQLDB mySQLDB,
SQLiteDB.Factory sqLiteDB,
H2DB.Factory h2DB,
PlanConfig config,
PluginLogger logger
) {
super(locale, sqLiteDB, h2DB, logger);
super(locale, sqLiteDB, logger);
this.config = config;
databases.add(mySQLDB);
databases.add(h2DB.usingDefaultFile());
databases.add(sqLiteDB.usingDefaultFile());
}

View File

@ -28,7 +28,6 @@ import net.playeranalytics.plugin.PlatformAbstractionLayer;
import net.playeranalytics.plugin.SpongePlatformLayer;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.server.PluginLogger;
import org.apache.maven.model.building.ModelBuildingException;
import org.bstats.sponge.Metrics;
import org.slf4j.Logger;
import org.spongepowered.api.Game;
@ -45,7 +44,6 @@ import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.scheduler.Task;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@ -117,11 +115,6 @@ public class PlanSponge implements PlanPlugin {
abstractionLayer = new SpongePlatformLayer(this, dataFolder, slf4jLogger);
logger = abstractionLayer.getPluginLogger();
runnableFactory = abstractionLayer.getRunnableFactory();
try {
new DependencyStartup(logger, abstractionLayer.getDependencyLoader()).loadDependencies();
} catch (IOException | ModelBuildingException e) {
java.util.logging.Logger.getGlobal().log(Level.SEVERE, e, () -> this.getClass().getSimpleName());
}
}
public void onEnable() {

View File

@ -39,16 +39,14 @@ public class SpongeDBSystem extends DBSystem {
Locale locale,
MySQLDB mySQLDB,
SQLiteDB.Factory sqLiteDB,
H2DB.Factory h2DB,
PlanConfig config,
PluginLogger logger
) {
super(locale, sqLiteDB, h2DB, logger);
super(locale, sqLiteDB, logger);
this.config = config;
databases.add(mySQLDB);
databases.add(sqLiteDB.usingDefaultFile());
databases.add(h2DB.usingDefaultFile());
}
@Override

View File

@ -33,12 +33,10 @@ import net.playeranalytics.plugin.PlatformAbstractionLayer;
import net.playeranalytics.plugin.VelocityPlatformLayer;
import net.playeranalytics.plugin.scheduling.RunnableFactory;
import net.playeranalytics.plugin.server.PluginLogger;
import org.apache.maven.model.building.ModelBuildingException;
import org.bstats.velocity.Metrics;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.logging.Level;
@ -96,12 +94,6 @@ public class PlanVelocity implements PlanPlugin {
logger = abstractionLayer.getPluginLogger();
runnableFactory = abstractionLayer.getRunnableFactory();
try {
new DependencyStartup(logger, abstractionLayer.getDependencyLoader()).loadDependencies();
} catch (IOException | ModelBuildingException e) {
java.util.logging.Logger.getGlobal().log(Level.SEVERE, e, () -> this.getClass().getSimpleName());
}
PlanVelocityComponent component = DaggerPlanVelocityComponent.builder()
.plan(this)
.abstractionLayer(abstractionLayer)