diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java index a501cc93a..021c10fb0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java @@ -57,10 +57,13 @@ import java.util.concurrent.CompletionException; */ public class AbstractStorage implements Storage { public static Storage create(LuckPermsPlugin plugin, AbstractDao backing) { + // make a base implementation Storage base = new AbstractStorage(plugin, backing); - Storage phased = PhasedStorage.wrap(base); + // wrap with a phaser + PhasedStorage phased = PhasedStorage.wrap(base); + // wrap with a buffer BufferedOutputStorage buffered = BufferedOutputStorage.wrap(phased, 250L); - plugin.getBootstrap().getScheduler().asyncRepeating(buffered, 2L); + plugin.getBootstrap().getScheduler().asyncRepeating(buffered.buffer(), 2L); return buffered; } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/H2ConnectionFactory.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/H2ConnectionFactory.java index d32120e8f..09dabe810 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/H2ConnectionFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/H2ConnectionFactory.java @@ -70,7 +70,7 @@ public class H2ConnectionFactory extends FlatfileConnectionFactory { if (this.connection == null || this.connection.isClosed()) { Connection connection = this.driver.connect("jdbc:h2:" + this.file.getAbsolutePath(), new Properties()); if (connection != null) { - this.connection = new NonClosableConnection(connection); + this.connection = NonClosableConnection.wrap(connection); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/NonClosableConnection.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/NonClosableConnection.java index d93a6406b..bf447e8d3 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/NonClosableConnection.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/NonClosableConnection.java @@ -25,305 +25,45 @@ package me.lucko.luckperms.common.storage.dao.sql.connection.file; -import java.sql.Array; -import java.sql.Blob; -import java.sql.CallableStatement; -import java.sql.Clob; +import java.lang.reflect.Proxy; import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.NClob; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.SQLWarning; -import java.sql.SQLXML; -import java.sql.Savepoint; -import java.sql.Statement; -import java.sql.Struct; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.Executor; -public final class NonClosableConnection implements Connection { - private final Connection delegate; +/** + * Represents a connection which cannot be closed using the standard {@link #close()} method. + */ +public interface NonClosableConnection extends Connection { - public NonClosableConnection(Connection delegate) { - this.delegate = delegate; - } - - @Override - public void close() { - - } - - public void shutdown() throws SQLException { - this.delegate.close(); - } - - // delegate - - @Override - public String getCatalog() throws SQLException { - return this.delegate.getCatalog(); - } - - @Override - public void commit() throws SQLException { - this.delegate.commit(); - } - - @Override - public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return this.delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); - } - - @Override - public String nativeSQL(String sql) throws SQLException { - return this.delegate.nativeSQL(sql); - } - - @Override - public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { - return this.delegate.prepareStatement(sql, autoGeneratedKeys); - } - - @Override - public Blob createBlob() throws SQLException { - return this.delegate.createBlob(); - } - - @Override - public Struct createStruct(String typeName, Object[] attributes) throws SQLException { - return this.delegate.createStruct(typeName, attributes); - } - - @Override - public int getTransactionIsolation() throws SQLException { - return this.delegate.getTransactionIsolation(); - } - - @Override - public boolean isWrapperFor(Class iface) throws SQLException { - return this.delegate.isWrapperFor(iface); - } - - @Override - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - return this.delegate.prepareStatement(sql, resultSetType, resultSetConcurrency); - } - - @Override - public void setHoldability(int holdability) throws SQLException { - this.delegate.setHoldability(holdability); - } - - @Override - public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - return this.delegate.prepareStatement(sql, columnIndexes); - } - - @Override - public void setSchema(String schema) throws SQLException { - this.delegate.setSchema(schema); - } - - @Override - public void abort(Executor executor) throws SQLException { - this.delegate.abort(executor); - } - - @Override - public void setTypeMap(Map> map) throws SQLException { - this.delegate.setTypeMap(map); - } - - @Override - public NClob createNClob() throws SQLException { - return this.delegate.createNClob(); - } - - @Override - public boolean isReadOnly() throws SQLException { - return this.delegate.isReadOnly(); - } - - @Override - public boolean getAutoCommit() throws SQLException { - return this.delegate.getAutoCommit(); - } - - @Override - public int getHoldability() throws SQLException { - return this.delegate.getHoldability(); - } - - @Override - public T unwrap(Class iface) throws SQLException { - return this.delegate.unwrap(iface); - } - - @Override - public Statement createStatement() throws SQLException { - return this.delegate.createStatement(); - } - - @Override - public SQLXML createSQLXML() throws SQLException { - return this.delegate.createSQLXML(); - } - - @Override - public boolean isClosed() throws SQLException { - return this.delegate.isClosed(); - } - - @Override - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return this.delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); - } - - @Override - public Properties getClientInfo() throws SQLException { - return this.delegate.getClientInfo(); - } - - @Override - public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { - this.delegate.setNetworkTimeout(executor, milliseconds); - } - - @Override - public String getSchema() throws SQLException { - return this.delegate.getSchema(); - } - - @Override - public String getClientInfo(String name) throws SQLException { - return this.delegate.getClientInfo(name); - } - - @Override - public Array createArrayOf(String typeName, Object[] elements) throws SQLException { - return this.delegate.createArrayOf(typeName, elements); - } - - @Override - public void rollback() throws SQLException { - this.delegate.rollback(); - } - - @Override - public boolean isValid(int timeout) throws SQLException { - return this.delegate.isValid(timeout); - } - - @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 CallableStatement prepareCall(String sql) throws SQLException { - return this.delegate.prepareCall(sql); - } - - @Override - public int getNetworkTimeout() throws SQLException { - return this.delegate.getNetworkTimeout(); - } - - @Override - public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { - return this.delegate.createStatement(resultSetType, resultSetConcurrency); - } - - @Override - public void setReadOnly(boolean readOnly) throws SQLException { - this.delegate.setReadOnly(readOnly); - } - - @Override - public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { - return this.delegate.prepareStatement(sql, columnNames); - } - - @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) throws SQLException { - return this.delegate.prepareCall(sql, resultSetType, resultSetConcurrency); - } - - @Override - public void setClientInfo(String name, String value) throws java.sql.SQLClientInfoException { - this.delegate.setClientInfo(name, value); - } - - @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 Clob createClob() throws SQLException { - return this.delegate.createClob(); - } - - @Override - public PreparedStatement prepareStatement(String sql) throws SQLException { - return this.delegate.prepareStatement(sql); - } - - @Override - public Map> getTypeMap() throws SQLException { - return this.delegate.getTypeMap(); - } - - @Override - public void setAutoCommit(boolean autoCommit) throws SQLException { - this.delegate.setAutoCommit(autoCommit); - } - - @Override - public void setClientInfo(Properties properties) throws java.sql.SQLClientInfoException { - this.delegate.setClientInfo(properties); - } - - @Override - public SQLWarning getWarnings() throws SQLException { - return this.delegate.getWarnings(); - } - - @Override - public void setTransactionIsolation(int level) throws SQLException { - this.delegate.setTransactionIsolation(level); - } - - @Override - public DatabaseMetaData getMetaData() throws SQLException { - return this.delegate.getMetaData(); - } - - @Override - public void setCatalog(String catalog) throws SQLException { - this.delegate.setCatalog(catalog); - } - - @Override - public void clearWarnings() throws SQLException { - this.delegate.clearWarnings(); + /** + * 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) { + return (NonClosableConnection) Proxy.newProxyInstance( + NonClosableConnection.class.getClassLoader(), + new Class[]{NonClosableConnection.class}, + (proxy, method, args) -> { + + // block calls directly to #close + if (method.getName().equals("close")) { + return null; + } + + // proxy calls to #shutdown to the real #close method + if (method.getName().equals("shutdown")) { + connection.close(); + return null; + } + + // delegate all other calls + return method.invoke(connection, args); + } + ); } + /** + * Actually {@link #close() closes} the underlying connection. + */ + void shutdown(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/SQLiteConnectionFactory.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/SQLiteConnectionFactory.java index 57c9e58ab..29e3af720 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/SQLiteConnectionFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/sql/connection/file/SQLiteConnectionFactory.java @@ -81,7 +81,7 @@ public class SQLiteConnectionFactory extends FlatfileConnectionFactory { if (this.connection == null || this.connection.isClosed()) { Connection connection = createConnection("jdbc:sqlite:" + this.file.getAbsolutePath()); if (connection != null) { - this.connection = new NonClosableConnection(connection); + this.connection = NonClosableConnection.wrap(connection); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/BufferedOutputStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/BufferedOutputStorage.java index 2836831a5..3e950e930 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/BufferedOutputStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/BufferedOutputStorage.java @@ -25,204 +25,116 @@ package me.lucko.luckperms.common.storage.wrappings; -import me.lucko.luckperms.api.HeldPermission; -import me.lucko.luckperms.api.LogEntry; -import me.lucko.luckperms.api.event.cause.CreationCause; -import me.lucko.luckperms.api.event.cause.DeletionCause; -import me.lucko.luckperms.common.actionlog.Log; -import me.lucko.luckperms.common.api.delegates.model.ApiStorage; import me.lucko.luckperms.common.buffers.Buffer; -import me.lucko.luckperms.common.bulkupdate.BulkUpdate; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.storage.Storage; -import me.lucko.luckperms.common.storage.dao.AbstractDao; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.lang.reflect.Proxy; import java.util.concurrent.CompletableFuture; /** * A storage wrapping that passes save tasks through a buffer */ -public class BufferedOutputStorage implements Storage, Runnable { - public static BufferedOutputStorage wrap(Storage storage, long flushTime) { - return new BufferedOutputStorage(storage, flushTime); +public interface BufferedOutputStorage extends Storage { + + /** + * Creates a new instance of {@link BufferedOutputStorage} which delegates called to the given + * {@link Storage} instance. + * + * @param delegate the delegate storage impl + * @param flushTime default flush time for the buffer. See {@link Buffer#flush(long)} + * @return the new buffered storage instance + */ + static BufferedOutputStorage wrap(Storage delegate, long flushTime) { + // create a buffer handler - we pass the unwrapped delegate here. + StorageBuffer buffer = new StorageBuffer(delegate, flushTime); + + // create and return a proxy instance which directs save calls through the buffer + return (BufferedOutputStorage) Proxy.newProxyInstance( + BufferedOutputStorage.class.getClassLoader(), + new Class[]{BufferedOutputStorage.class}, + (proxy, method, args) -> { + // run save methods through the buffer instance + switch (method.getName()) { + case "saveUser": + return buffer.saveUser((User) args[0]); + case "saveGroup": + return buffer.saveGroup((Group) args[0]); + case "saveTrack": + return buffer.saveTrack((Track) args[0]); + } + + // provide implementation of #noBuffer + if (method.getName().equals("noBuffer")) { + return delegate; + } + + // provide implementation of #buffer + if (method.getName().equals("buffer")) { + return buffer; + } + + // flush the buffer on shutdown + if (method.getName().equals("shutdown")) { + buffer.forceFlush(); + // ...and then delegate + } + + // delegate the call + return method.invoke(delegate, args); + } + ); } - private final Storage delegate; + /** + * Gets the buffer behind this instance + * + * @return the buffer + */ + StorageBuffer buffer(); - private final long flushTime; + final class StorageBuffer implements Runnable { + private final long flushTime; - private final Buffer userOutputBuffer = Buffer.of(user -> BufferedOutputStorage.this.delegate.saveUser(user).join()); - private final Buffer groupOutputBuffer = Buffer.of(group -> BufferedOutputStorage.this.delegate.saveGroup(group).join()); - private final Buffer trackOutputBuffer = Buffer.of(track -> BufferedOutputStorage.this.delegate.saveTrack(track).join()); + private final Buffer userOutputBuffer; + private final Buffer groupOutputBuffer; + private final Buffer trackOutputBuffer; - private BufferedOutputStorage(Storage delegate, long flushTime) { - this.delegate = delegate; - this.flushTime = flushTime; + private StorageBuffer(Storage delegate, long flushTime) { + this.flushTime = flushTime; + this.userOutputBuffer = Buffer.of(user -> delegate.saveUser(user).join()); + this.groupOutputBuffer = Buffer.of(group -> delegate.saveGroup(group).join()); + this.trackOutputBuffer = Buffer.of(track -> delegate.saveTrack(track).join()); + } + + public void run() { + flush(this.flushTime); + } + + public void forceFlush() { + flush(-1); + } + + public void flush(long flushTime) { + this.userOutputBuffer.flush(flushTime); + this.groupOutputBuffer.flush(flushTime); + this.trackOutputBuffer.flush(flushTime); + } + + // copy the required implementation methods from the Storage interface + + private CompletableFuture saveUser(User user) { + return this.userOutputBuffer.enqueue(user); + } + + private CompletableFuture saveGroup(Group group) { + return this.groupOutputBuffer.enqueue(group); + } + + private CompletableFuture saveTrack(Track track) { + return this.trackOutputBuffer.enqueue(track); + } } - - @Override - public void run() { - flush(this.flushTime); - } - - public void forceFlush() { - flush(-1); - } - - public void flush(long flushTime) { - this.userOutputBuffer.flush(flushTime); - this.groupOutputBuffer.flush(flushTime); - this.trackOutputBuffer.flush(flushTime); - } - - @Override - public Storage noBuffer() { - return this.delegate; - } - - @Override - public void shutdown() { - forceFlush(); - this.delegate.shutdown(); - } - - @Override - public CompletableFuture saveUser(User user) { - return this.userOutputBuffer.enqueue(user); - } - - @Override - public CompletableFuture saveGroup(Group group) { - return this.groupOutputBuffer.enqueue(group); - } - - @Override - public CompletableFuture saveTrack(Track track) { - return this.trackOutputBuffer.enqueue(track); - } - - // delegate - - @Override - public AbstractDao getDao() { - return this.delegate.getDao(); - } - - @Override - public CompletableFuture> getUniqueUsers() { - return this.delegate.getUniqueUsers(); - } - - @Override - public CompletableFuture> loadTrack(String name) { - return this.delegate.loadTrack(name); - } - - @Override - public CompletableFuture>> getUsersWithPermission(String permission) { - return this.delegate.getUsersWithPermission(permission); - } - - @Override - public CompletableFuture>> getGroupsWithPermission(String permission) { - return this.delegate.getGroupsWithPermission(permission); - } - - @Override - public CompletableFuture applyBulkUpdate(BulkUpdate bulkUpdate) { - return this.delegate.applyBulkUpdate(bulkUpdate); - } - - @Override - public CompletableFuture saveUUIDData(UUID uuid, String username) { - return this.delegate.saveUUIDData(uuid, username); - } - - @Override - public CompletableFuture createAndLoadGroup(String name, CreationCause cause) { - return this.delegate.createAndLoadGroup(name, cause); - } - - @Override - public Map getMeta() { - return this.delegate.getMeta(); - } - - @Override - public CompletableFuture deleteGroup(Group group, DeletionCause cause) { - return this.delegate.deleteGroup(group, cause); - } - - @Override - public CompletableFuture getUUID(String username) { - return this.delegate.getUUID(username); - } - - @Override - public CompletableFuture loadUser(UUID uuid, String username) { - return this.delegate.loadUser(uuid, username); - } - - @Override - public CompletableFuture createAndLoadTrack(String name, CreationCause cause) { - return this.delegate.createAndLoadTrack(name, cause); - } - - @Override - public CompletableFuture getLog() { - return this.delegate.getLog(); - } - - @Override - public ApiStorage getApiDelegate() { - return this.delegate.getApiDelegate(); - } - - @Override - public CompletableFuture getName(UUID uuid) { - return this.delegate.getName(uuid); - } - - @Override - public String getName() { - return this.delegate.getName(); - } - - @Override - public CompletableFuture loadAllTracks() { - return this.delegate.loadAllTracks(); - } - - @Override - public void init() { - this.delegate.init(); - } - - @Override - public CompletableFuture deleteTrack(Track track, DeletionCause cause) { - return this.delegate.deleteTrack(track, cause); - } - - @Override - public CompletableFuture logAction(LogEntry entry) { - return this.delegate.logAction(entry); - } - - @Override - public CompletableFuture loadAllGroups() { - return this.delegate.loadAllGroups(); - } - - @Override - public CompletableFuture> loadGroup(String name) { - return this.delegate.loadGroup(name); - } - } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java index fabe37efe..7db0e552c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java @@ -25,294 +25,70 @@ package me.lucko.luckperms.common.storage.wrappings; -import me.lucko.luckperms.api.HeldPermission; -import me.lucko.luckperms.api.LogEntry; -import me.lucko.luckperms.api.event.cause.CreationCause; -import me.lucko.luckperms.api.event.cause.DeletionCause; -import me.lucko.luckperms.common.actionlog.Log; -import me.lucko.luckperms.common.api.delegates.model.ApiStorage; -import me.lucko.luckperms.common.bulkupdate.BulkUpdate; -import me.lucko.luckperms.common.model.Group; -import me.lucko.luckperms.common.model.Track; -import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.storage.Storage; -import me.lucko.luckperms.common.storage.dao.AbstractDao; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; +import java.lang.reflect.Proxy; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** - * A storage wrapping that ensures all tasks are completed before - * {@link Storage#shutdown()} is called. + * A storage wrapping that ensures all tasks are completed before {@link Storage#shutdown()} is called. */ -public class PhasedStorage implements Storage { - public static PhasedStorage wrap(Storage storage) { - return new PhasedStorage(storage); - } +public interface PhasedStorage extends Storage { - private final Storage delegate; - private final Phaser phaser = new Phaser(); + /** + * Creates a new instance of {@link PhasedStorage} which delegates called to the given + * {@link Storage} instance. + * + * @param delegate the delegate storage impl + * @return the new phased storage instance + */ + static PhasedStorage wrap(Storage delegate) { + // create a new phaser to be used by the instance + Phaser phaser = new Phaser(); - private PhasedStorage(Storage delegate) { - this.delegate = delegate; - } + // create and return a proxy instance which directs save calls through the phaser + return (PhasedStorage) Proxy.newProxyInstance( + PhasedStorage.class.getClassLoader(), + new Class[]{PhasedStorage.class}, + (proxy, method, args) -> { - @Override - public AbstractDao getDao() { - return this.delegate.getDao(); - } + // provide implementation of #noBuffer + if (method.getName().equals("noBuffer")) { + return delegate; + } - @Override - public ApiStorage getApiDelegate() { - return this.delegate.getApiDelegate(); - } + // direct delegation + switch (method.getName()) { + case "getDao": + case "getApiDelegate": + case "getName": + case "init": + case "getMeta": + return method.invoke(proxy, args); + } - @Override - public String getName() { - return this.delegate.getName(); - } + // await the phaser on shutdown + if (method.getName().equals("shutdown")) { + try { + phaser.awaitAdvanceInterruptibly(phaser.getPhase(), 10, TimeUnit.SECONDS); + } catch (InterruptedException | TimeoutException e) { + e.printStackTrace(); + } - @Override - public Storage noBuffer() { - return this; - } + delegate.shutdown(); + return null; + } - @Override - public void init() { - this.delegate.init(); - } - - @Override - public void shutdown() { - // Wait for other threads to finish. - try { - this.phaser.awaitAdvanceInterruptibly(this.phaser.getPhase(), 10, TimeUnit.SECONDS); - } catch (InterruptedException | TimeoutException e) { - e.printStackTrace(); - } - - this.delegate.shutdown(); - } - - @Override - public Map getMeta() { - return this.delegate.getMeta(); - } - - @Override - public CompletableFuture logAction(LogEntry entry) { - this.phaser.register(); - try { - return this.delegate.logAction(entry); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture getLog() { - this.phaser.register(); - try { - return this.delegate.getLog(); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture applyBulkUpdate(BulkUpdate bulkUpdate) { - this.phaser.register(); - try { - return this.delegate.applyBulkUpdate(bulkUpdate); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture loadUser(UUID uuid, String username) { - this.phaser.register(); - try { - return this.delegate.loadUser(uuid, username); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture saveUser(User user) { - this.phaser.register(); - try { - return this.delegate.saveUser(user); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture> getUniqueUsers() { - this.phaser.register(); - try { - return this.delegate.getUniqueUsers(); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture>> getUsersWithPermission(String permission) { - this.phaser.register(); - try { - return this.delegate.getUsersWithPermission(permission); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture createAndLoadGroup(String name, CreationCause cause) { - this.phaser.register(); - try { - return this.delegate.createAndLoadGroup(name, cause); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture> loadGroup(String name) { - this.phaser.register(); - try { - return this.delegate.loadGroup(name); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture loadAllGroups() { - this.phaser.register(); - try { - return this.delegate.loadAllGroups(); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture saveGroup(Group group) { - this.phaser.register(); - try { - return this.delegate.saveGroup(group); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture deleteGroup(Group group, DeletionCause cause) { - this.phaser.register(); - try { - return this.delegate.deleteGroup(group, cause); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture>> getGroupsWithPermission(String permission) { - this.phaser.register(); - try { - return this.delegate.getGroupsWithPermission(permission); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture createAndLoadTrack(String name, CreationCause cause) { - this.phaser.register(); - try { - return this.delegate.createAndLoadTrack(name, cause); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture> loadTrack(String name) { - this.phaser.register(); - try { - return this.delegate.loadTrack(name); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture loadAllTracks() { - this.phaser.register(); - try { - return this.delegate.loadAllTracks(); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture saveTrack(Track track) { - this.phaser.register(); - try { - return this.delegate.saveTrack(track); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture deleteTrack(Track track, DeletionCause cause) { - this.phaser.register(); - try { - return this.delegate.deleteTrack(track, cause); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture saveUUIDData(UUID uuid, String username) { - this.phaser.register(); - try { - return this.delegate.saveUUIDData(uuid, username); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture getUUID(String username) { - this.phaser.register(); - try { - return this.delegate.getUUID(username); - } finally { - this.phaser.arriveAndDeregister(); - } - } - - @Override - public CompletableFuture getName(UUID uuid) { - this.phaser.register(); - try { - return this.delegate.getName(uuid); - } finally { - this.phaser.arriveAndDeregister(); - } + // for all other methods, run the call via the phaser + phaser.register(); + try { + return method.invoke(delegate, args); + } finally { + phaser.arriveAndDeregister(); + } + } + ); } }