mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-12-29 12:37:40 +01:00
Cleanup flatfile database handling
This commit is contained in:
parent
c39749e526
commit
d1b53f65ae
@ -42,7 +42,7 @@ import me.lucko.luckperms.common.storage.implementation.split.SplitStorage;
|
|||||||
import me.lucko.luckperms.common.storage.implementation.split.SplitStorageType;
|
import me.lucko.luckperms.common.storage.implementation.split.SplitStorageType;
|
||||||
import me.lucko.luckperms.common.storage.implementation.sql.SqlStorage;
|
import me.lucko.luckperms.common.storage.implementation.sql.SqlStorage;
|
||||||
import me.lucko.luckperms.common.storage.implementation.sql.connection.file.H2ConnectionFactory;
|
import me.lucko.luckperms.common.storage.implementation.sql.connection.file.H2ConnectionFactory;
|
||||||
import me.lucko.luckperms.common.storage.implementation.sql.connection.file.SQLiteConnectionFactory;
|
import me.lucko.luckperms.common.storage.implementation.sql.connection.file.SqliteConnectionFactory;
|
||||||
import me.lucko.luckperms.common.storage.implementation.sql.connection.hikari.MariaDbConnectionFactory;
|
import me.lucko.luckperms.common.storage.implementation.sql.connection.hikari.MariaDbConnectionFactory;
|
||||||
import me.lucko.luckperms.common.storage.implementation.sql.connection.hikari.MySqlConnectionFactory;
|
import me.lucko.luckperms.common.storage.implementation.sql.connection.hikari.MySqlConnectionFactory;
|
||||||
import me.lucko.luckperms.common.storage.implementation.sql.connection.hikari.PostgreConnectionFactory;
|
import me.lucko.luckperms.common.storage.implementation.sql.connection.hikari.PostgreConnectionFactory;
|
||||||
@ -108,13 +108,13 @@ public class StorageFactory {
|
|||||||
case SQLITE:
|
case SQLITE:
|
||||||
return new SqlStorage(
|
return new SqlStorage(
|
||||||
this.plugin,
|
this.plugin,
|
||||||
new SQLiteConnectionFactory(this.plugin, this.plugin.getBootstrap().getDataDirectory().resolve("luckperms-sqlite.db")),
|
new SqliteConnectionFactory(this.plugin.getBootstrap().getDataDirectory().resolve("luckperms-sqlite.db")),
|
||||||
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
||||||
);
|
);
|
||||||
case H2:
|
case H2:
|
||||||
return new SqlStorage(
|
return new SqlStorage(
|
||||||
this.plugin,
|
this.plugin,
|
||||||
new H2ConnectionFactory(this.plugin, this.plugin.getBootstrap().getDataDirectory().resolve("luckperms-h2")),
|
new H2ConnectionFactory(this.plugin.getBootstrap().getDataDirectory().resolve("luckperms-h2")),
|
||||||
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
this.plugin.getConfiguration().get(ConfigKeys.SQL_TABLE_PREFIX)
|
||||||
);
|
);
|
||||||
case POSTGRESQL:
|
case POSTGRESQL:
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.common.storage.implementation.sql.connection.file;
|
package me.lucko.luckperms.common.storage.implementation.sql.connection.file;
|
||||||
|
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
|
||||||
import me.lucko.luckperms.common.storage.implementation.sql.connection.ConnectionFactory;
|
import me.lucko.luckperms.common.storage.implementation.sql.connection.ConnectionFactory;
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
@ -34,28 +33,74 @@ import net.kyori.adventure.text.format.NamedTextColor;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract {@link ConnectionFactory} using a file based database driver.
|
||||||
|
*/
|
||||||
abstract class FlatfileConnectionFactory implements ConnectionFactory {
|
abstract class FlatfileConnectionFactory implements ConnectionFactory {
|
||||||
protected static final DecimalFormat DF = new DecimalFormat("#.##");
|
/** Format used for formatting database file size. */
|
||||||
|
protected static final DecimalFormat FILE_SIZE_FORMAT = new DecimalFormat("#.##");
|
||||||
|
|
||||||
protected final Path file;
|
/** The current open connection, if any */
|
||||||
|
private NonClosableConnection connection;
|
||||||
|
/** The path to the database file */
|
||||||
|
private final Path file;
|
||||||
|
|
||||||
FlatfileConnectionFactory(Path file) {
|
FlatfileConnectionFactory(Path file) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void init(LuckPermsPlugin plugin) {
|
* Creates a connection to the database.
|
||||||
|
*
|
||||||
|
* @param file the database file
|
||||||
|
* @return the connection
|
||||||
|
* @throws SQLException if any error occurs
|
||||||
|
*/
|
||||||
|
protected abstract Connection createConnection(Path file) throws SQLException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Connection getConnection() throws SQLException {
|
||||||
|
NonClosableConnection connection = this.connection;
|
||||||
|
if (connection == null || connection.isClosed()) {
|
||||||
|
connection = new NonClosableConnection(createConnection(this.file));
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() throws Exception {
|
||||||
|
if (this.connection != null) {
|
||||||
|
this.connection.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the path of the file the database driver actually ends up writing to.
|
||||||
|
*
|
||||||
|
* @return the write file
|
||||||
|
*/
|
||||||
protected Path getWriteFile() {
|
protected Path getWriteFile() {
|
||||||
return this.file;
|
return this.file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void migrateOldDatabaseFile(String oldName) {
|
||||||
|
Path oldFile = getWriteFile().getParent().resolve(oldName);
|
||||||
|
if (Files.exists(oldFile)) {
|
||||||
|
try {
|
||||||
|
Files.move(oldFile, getWriteFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Component, Component> getMeta() {
|
public Map<Component, Component> getMeta() {
|
||||||
String fileSize;
|
String fileSize;
|
||||||
@ -69,7 +114,7 @@ abstract class FlatfileConnectionFactory implements ConnectionFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double size = length / 1048576D;
|
double size = length / 1048576D;
|
||||||
fileSize = DF.format(size) + "MB";
|
fileSize = FILE_SIZE_FORMAT.format(size) + "MB";
|
||||||
} else {
|
} else {
|
||||||
fileSize = "0MB";
|
fileSize = "0MB";
|
||||||
}
|
}
|
||||||
|
@ -29,47 +29,19 @@ import me.lucko.luckperms.common.dependencies.Dependency;
|
|||||||
import me.lucko.luckperms.common.dependencies.classloader.IsolatedClassLoader;
|
import me.lucko.luckperms.common.dependencies.classloader.IsolatedClassLoader;
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.Driver;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class H2ConnectionFactory extends FlatfileConnectionFactory {
|
public class H2ConnectionFactory extends FlatfileConnectionFactory {
|
||||||
|
private Constructor<?> connectionConstructor;
|
||||||
|
|
||||||
// the driver used to obtain connections
|
public H2ConnectionFactory(Path file) {
|
||||||
private final Driver driver;
|
|
||||||
// the active connection
|
|
||||||
private NonClosableConnection connection;
|
|
||||||
|
|
||||||
public H2ConnectionFactory(LuckPermsPlugin plugin, Path file) {
|
|
||||||
super(file);
|
super(file);
|
||||||
|
|
||||||
// backwards compat
|
|
||||||
Path data = file.getParent().resolve("luckperms.db.mv.db");
|
|
||||||
if (Files.exists(data)) {
|
|
||||||
try {
|
|
||||||
Files.move(data, getWriteFile());
|
|
||||||
} catch (IOException e) {
|
|
||||||
plugin.getLogger().warn("Unable to move old database", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup the classloader
|
|
||||||
IsolatedClassLoader classLoader = plugin.getDependencyManager().obtainClassLoaderWith(EnumSet.of(Dependency.H2_DRIVER));
|
|
||||||
try {
|
|
||||||
Class<?> driverClass = classLoader.loadClass("org.h2.Driver");
|
|
||||||
Method loadMethod = driverClass.getMethod("load");
|
|
||||||
this.driver = (Driver) loadMethod.invoke(null);
|
|
||||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -78,36 +50,39 @@ public class H2ConnectionFactory extends FlatfileConnectionFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Connection getConnection() throws SQLException {
|
public void init(LuckPermsPlugin plugin) {
|
||||||
if (this.connection == null || this.connection.isClosed()) {
|
migrateOldDatabaseFile("luckperms.db.mv.db");
|
||||||
Connection connection = this.driver.connect("jdbc:h2:" + this.file.toString(), new Properties());
|
|
||||||
if (connection != null) {
|
|
||||||
this.connection = NonClosableConnection.wrap(connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.connection == null) {
|
IsolatedClassLoader classLoader = plugin.getDependencyManager().obtainClassLoaderWith(EnumSet.of(Dependency.H2_DRIVER));
|
||||||
throw new SQLException("Unable to get a connection.");
|
try {
|
||||||
|
Class<?> connectionClass = classLoader.loadClass("org.h2.jdbc.JdbcConnection");
|
||||||
|
this.connectionConstructor = connectionClass.getConstructor(String.class, Properties.class);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown() throws Exception {
|
protected Connection createConnection(Path file) throws SQLException {
|
||||||
if (this.connection != null) {
|
try {
|
||||||
this.connection.shutdown();
|
return (Connection) this.connectionConstructor.newInstance("jdbc:h2:" + file.toString(), new Properties());
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
if (e.getCause() instanceof SQLException) {
|
||||||
|
throw ((SQLException) e.getCause());
|
||||||
}
|
}
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Path getWriteFile() {
|
||||||
|
// h2 appends '.mv.db' to the end of the database name
|
||||||
|
Path writeFile = super.getWriteFile();
|
||||||
|
return writeFile.getParent().resolve(writeFile.getFileName().toString() + ".mv.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Function<String, String> getStatementProcessor() {
|
public Function<String, String> getStatementProcessor() {
|
||||||
return s -> s.replace("'", "`");
|
return s -> s.replace("'", "`");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Path getWriteFile() {
|
|
||||||
// h2 appends this to the end of the database file
|
|
||||||
return super.file.getParent().resolve(super.file.getFileName().toString() + ".mv.db");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,63 +25,32 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.common.storage.implementation.sql.connection.file;
|
package me.lucko.luckperms.common.storage.implementation.sql.connection.file;
|
||||||
|
|
||||||
import net.bytebuddy.ByteBuddy;
|
import java.sql.Array;
|
||||||
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
|
import java.sql.Blob;
|
||||||
import net.bytebuddy.implementation.MethodDelegation;
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.Clob;
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.DatabaseMetaData;
|
||||||
|
import java.sql.NClob;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLClientInfoException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.SQLWarning;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
|
import java.sql.SQLXML;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isFinal;
|
import java.sql.Savepoint;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
import java.sql.Statement;
|
||||||
|
import java.sql.Struct;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around a {@link Connection} which blocks usage of the default {@link #close()} method.
|
* A wrapper around a {@link Connection} which blocks usage of the default {@link #close()} method.
|
||||||
*/
|
*/
|
||||||
public abstract class NonClosableConnection implements Connection {
|
public class NonClosableConnection implements Connection {
|
||||||
|
private final Connection delegate;
|
||||||
|
|
||||||
private static final MethodHandle CONSTRUCTOR;
|
public NonClosableConnection(Connection delegate) {
|
||||||
static {
|
|
||||||
// construct an implementation of NonClosableConnection
|
|
||||||
Class<? extends NonClosableConnection> implClass = new ByteBuddy()
|
|
||||||
.subclass(NonClosableConnection.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
|
|
||||||
.name(NonClosableConnection.class.getName() + "Impl")
|
|
||||||
.method(not(isFinal()).and(not(isDeclaredBy(Object.class))))
|
|
||||||
.intercept(MethodDelegation.toField("delegate"))
|
|
||||||
.make()
|
|
||||||
.load(NonClosableConnection.class.getClassLoader())
|
|
||||||
.getLoaded();
|
|
||||||
|
|
||||||
try {
|
|
||||||
CONSTRUCTOR = MethodHandles.publicLookup().in(implClass)
|
|
||||||
.findConstructor(implClass, MethodType.methodType(void.class, Connection.class))
|
|
||||||
.asType(MethodType.methodType(NonClosableConnection.class, Connection.class));
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
throw new ExceptionInInitializerError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a {@link NonClosableConnection} that delegates calls to the given {@link Connection}.
|
|
||||||
*
|
|
||||||
* @param connection the connection to wrap
|
|
||||||
* @return a non closable connection
|
|
||||||
*/
|
|
||||||
static NonClosableConnection wrap(Connection connection) {
|
|
||||||
try {
|
|
||||||
return (NonClosableConnection) CONSTRUCTOR.invokeExact(connection);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final Connection delegate;
|
|
||||||
|
|
||||||
protected NonClosableConnection(Connection delegate) {
|
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,4 +79,58 @@ public abstract class NonClosableConnection implements Connection {
|
|||||||
}
|
}
|
||||||
return this.delegate.unwrap(iface);
|
return this.delegate.unwrap(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forward to the delegate connection
|
||||||
|
@Override public Statement createStatement() throws SQLException { return this.delegate.createStatement(); }
|
||||||
|
@Override public PreparedStatement prepareStatement(String sql) throws SQLException { return this.delegate.prepareStatement(sql); }
|
||||||
|
@Override public CallableStatement prepareCall(String sql) throws SQLException { return this.delegate.prepareCall(sql); }
|
||||||
|
@Override public String nativeSQL(String sql) throws SQLException { return this.delegate.nativeSQL(sql); }
|
||||||
|
@Override public void setAutoCommit(boolean autoCommit) throws SQLException { this.delegate.setAutoCommit(autoCommit); }
|
||||||
|
@Override public boolean getAutoCommit() throws SQLException { return this.delegate.getAutoCommit(); }
|
||||||
|
@Override public void commit() throws SQLException { this.delegate.commit(); }
|
||||||
|
@Override public void rollback() throws SQLException { this.delegate.rollback(); }
|
||||||
|
@Override public boolean isClosed() throws SQLException { return this.delegate.isClosed(); }
|
||||||
|
@Override public DatabaseMetaData getMetaData() throws SQLException { return this.delegate.getMetaData(); }
|
||||||
|
@Override public void setReadOnly(boolean readOnly) throws SQLException { this.delegate.setReadOnly(readOnly); }
|
||||||
|
@Override public boolean isReadOnly() throws SQLException { return this.delegate.isReadOnly(); }
|
||||||
|
@Override public void setCatalog(String catalog) throws SQLException { this.delegate.setCatalog(catalog); }
|
||||||
|
@Override public String getCatalog() throws SQLException { return this.delegate.getCatalog(); }
|
||||||
|
@Override public void setTransactionIsolation(int level) throws SQLException { this.delegate.setTransactionIsolation(level); }
|
||||||
|
@Override public int getTransactionIsolation() throws SQLException { return this.delegate.getTransactionIsolation(); }
|
||||||
|
@Override public SQLWarning getWarnings() throws SQLException { return this.delegate.getWarnings(); }
|
||||||
|
@Override public void clearWarnings() throws SQLException { this.delegate.clearWarnings(); }
|
||||||
|
@Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return this.delegate.createStatement(resultSetType, resultSetConcurrency); }
|
||||||
|
@Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return this.delegate.prepareStatement(sql, resultSetType, resultSetConcurrency); }
|
||||||
|
@Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return this.delegate.prepareCall(sql, resultSetType, resultSetConcurrency); }
|
||||||
|
@Override public Map<String, Class<?>> getTypeMap() throws SQLException { return this.delegate.getTypeMap(); }
|
||||||
|
@Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { this.delegate.setTypeMap(map); }
|
||||||
|
@Override public void setHoldability(int holdability) throws SQLException { this.delegate.setHoldability(holdability); }
|
||||||
|
@Override public int getHoldability() throws SQLException { return this.delegate.getHoldability(); }
|
||||||
|
@Override public Savepoint setSavepoint() throws SQLException { return this.delegate.setSavepoint(); }
|
||||||
|
@Override public Savepoint setSavepoint(String name) throws SQLException { return this.delegate.setSavepoint(name); }
|
||||||
|
@Override public void rollback(Savepoint savepoint) throws SQLException { this.delegate.rollback(savepoint); }
|
||||||
|
@Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { this.delegate.releaseSavepoint(savepoint); }
|
||||||
|
@Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return this.delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); }
|
||||||
|
@Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return this.delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); }
|
||||||
|
@Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return this.delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); }
|
||||||
|
@Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { return this.delegate.prepareStatement(sql, autoGeneratedKeys); }
|
||||||
|
@Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return this.delegate.prepareStatement(sql, columnIndexes); }
|
||||||
|
@Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return this.delegate.prepareStatement(sql, columnNames); }
|
||||||
|
@Override public Clob createClob() throws SQLException { return this.delegate.createClob(); }
|
||||||
|
@Override public Blob createBlob() throws SQLException { return this.delegate.createBlob(); }
|
||||||
|
@Override public NClob createNClob() throws SQLException { return this.delegate.createNClob(); }
|
||||||
|
@Override public SQLXML createSQLXML() throws SQLException { return this.delegate.createSQLXML(); }
|
||||||
|
@Override public boolean isValid(int timeout) throws SQLException { return this.delegate.isValid(timeout); }
|
||||||
|
@Override public void setClientInfo(String name, String value) throws SQLClientInfoException { this.delegate.setClientInfo(name, value); }
|
||||||
|
@Override public void setClientInfo(Properties properties) throws SQLClientInfoException { this.delegate.setClientInfo(properties); }
|
||||||
|
@Override public String getClientInfo(String name) throws SQLException { return this.delegate.getClientInfo(name); }
|
||||||
|
@Override public Properties getClientInfo() throws SQLException { return this.delegate.getClientInfo(); }
|
||||||
|
@Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { return this.delegate.createArrayOf(typeName, elements); }
|
||||||
|
@Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { return this.delegate.createStruct(typeName, attributes); }
|
||||||
|
@Override public void setSchema(String schema) throws SQLException { this.delegate.setSchema(schema); }
|
||||||
|
@Override public String getSchema() throws SQLException { return this.delegate.getSchema(); }
|
||||||
|
@Override public void abort(Executor executor) throws SQLException { this.delegate.abort(executor); }
|
||||||
|
@Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { this.delegate.setNetworkTimeout(executor, milliseconds); }
|
||||||
|
@Override public int getNetworkTimeout() throws SQLException { return this.delegate.getNetworkTimeout(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,7 @@ import me.lucko.luckperms.common.dependencies.Dependency;
|
|||||||
import me.lucko.luckperms.common.dependencies.classloader.IsolatedClassLoader;
|
import me.lucko.luckperms.common.dependencies.classloader.IsolatedClassLoader;
|
||||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@ -40,34 +37,11 @@ import java.util.EnumSet;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class SQLiteConnectionFactory extends FlatfileConnectionFactory {
|
public class SqliteConnectionFactory extends FlatfileConnectionFactory {
|
||||||
|
private Constructor<?> connectionConstructor;
|
||||||
|
|
||||||
// the method invoked to obtain new connection instances
|
public SqliteConnectionFactory(Path file) {
|
||||||
private final Method createConnectionMethod;
|
|
||||||
// the active connection
|
|
||||||
private NonClosableConnection connection;
|
|
||||||
|
|
||||||
public SQLiteConnectionFactory(LuckPermsPlugin plugin, Path file) {
|
|
||||||
super(file);
|
super(file);
|
||||||
|
|
||||||
// backwards compat
|
|
||||||
Path data = file.getParent().resolve("luckperms.sqlite");
|
|
||||||
if (Files.exists(data)) {
|
|
||||||
try {
|
|
||||||
Files.move(data, file);
|
|
||||||
} catch (IOException e) {
|
|
||||||
plugin.getLogger().warn("Unable to move old database", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup the classloader
|
|
||||||
IsolatedClassLoader classLoader = plugin.getDependencyManager().obtainClassLoaderWith(EnumSet.of(Dependency.SQLITE_DRIVER));
|
|
||||||
try {
|
|
||||||
Class<?> jdcbClass = classLoader.loadClass("org.sqlite.JDBC");
|
|
||||||
this.createConnectionMethod = jdcbClass.getMethod("createConnection", String.class, Properties.class);
|
|
||||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -75,12 +49,24 @@ public class SQLiteConnectionFactory extends FlatfileConnectionFactory {
|
|||||||
return "SQLite";
|
return "SQLite";
|
||||||
}
|
}
|
||||||
|
|
||||||
private Connection createConnection(String url) throws SQLException {
|
@Override
|
||||||
|
public void init(LuckPermsPlugin plugin) {
|
||||||
|
migrateOldDatabaseFile("luckperms.sqlite");
|
||||||
|
|
||||||
|
IsolatedClassLoader classLoader = plugin.getDependencyManager().obtainClassLoaderWith(EnumSet.of(Dependency.SQLITE_DRIVER));
|
||||||
try {
|
try {
|
||||||
return (Connection) this.createConnectionMethod.invoke(null, url, new Properties());
|
Class<?> connectionClass = classLoader.loadClass("org.sqlite.jdbc4.JDBC4Connection");
|
||||||
} catch (IllegalAccessException e) {
|
this.connectionConstructor = connectionClass.getConstructor(String.class, String.class, Properties.class);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} catch (InvocationTargetException e) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Connection createConnection(Path file) throws SQLException {
|
||||||
|
try {
|
||||||
|
return (Connection) this.connectionConstructor.newInstance("jdbc:sqlite:" + file.toString(), file.toString(), new Properties());
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
if (e.getCause() instanceof SQLException) {
|
if (e.getCause() instanceof SQLException) {
|
||||||
throw ((SQLException) e.getCause());
|
throw ((SQLException) e.getCause());
|
||||||
}
|
}
|
||||||
@ -88,32 +74,8 @@ public class SQLiteConnectionFactory extends FlatfileConnectionFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized Connection getConnection() throws SQLException {
|
|
||||||
if (this.connection == null || this.connection.isClosed()) {
|
|
||||||
Connection connection = createConnection("jdbc:sqlite:" + this.file.toString());
|
|
||||||
if (connection != null) {
|
|
||||||
this.connection = NonClosableConnection.wrap(connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.connection == null) {
|
|
||||||
throw new SQLException("Unable to get a connection.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown() throws Exception {
|
|
||||||
if (this.connection != null) {
|
|
||||||
this.connection.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Function<String, String> getStatementProcessor() {
|
public Function<String, String> getStatementProcessor() {
|
||||||
return s -> s.replace("'", "`");
|
return s -> s.replace("'", "`");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user