diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/GameModeChangeListener.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/GameModeChangeListener.java index adb2d7617..40ddc29d5 100644 --- a/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/GameModeChangeListener.java +++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/GameModeChangeListener.java @@ -17,7 +17,10 @@ package com.djrapitops.plan.system.listeners.bukkit; import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction; import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.settings.config.WorldAliasSettings; import com.djrapitops.plugin.logging.L; import com.djrapitops.plugin.logging.error.ErrorHandler; @@ -39,14 +42,20 @@ import java.util.UUID; public class GameModeChangeListener implements Listener { private final WorldAliasSettings worldAliasSettings; + private final ServerInfo serverInfo; + private final DBSystem dbSystem; private final ErrorHandler errorHandler; @Inject public GameModeChangeListener( WorldAliasSettings worldAliasSettings, + ServerInfo serverInfo, + DBSystem dbSystem, ErrorHandler errorHandler ) { this.worldAliasSettings = worldAliasSettings; + this.serverInfo = serverInfo; + this.dbSystem = dbSystem; this.errorHandler = errorHandler; } @@ -69,6 +78,7 @@ public class GameModeChangeListener implements Listener { String gameMode = event.getNewGameMode().name(); String worldName = player.getWorld().getName(); + dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), worldName)); worldAliasSettings.addWorld(worldName); Optional cachedSession = SessionCache.getCachedSession(uuid); diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/PlayerOnlineListener.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/PlayerOnlineListener.java index a7d1377bb..b6a921f6b 100644 --- a/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/PlayerOnlineListener.java +++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/PlayerOnlineListener.java @@ -17,7 +17,9 @@ package com.djrapitops.plan.system.listeners.bukkit; import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction; import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.processing.Processing; import com.djrapitops.plan.system.processing.processors.Processors; @@ -51,6 +53,7 @@ public class PlayerOnlineListener implements Listener { private final Processors processors; private final Processing processing; private final ServerInfo serverInfo; + private final DBSystem dbSystem; private final SessionCache sessionCache; private final ErrorHandler errorHandler; private final Status status; @@ -62,6 +65,7 @@ public class PlayerOnlineListener implements Listener { Processors processors, Processing processing, ServerInfo serverInfo, + DBSystem dbSystem, SessionCache sessionCache, Status status, RunnableFactory runnableFactory, @@ -71,6 +75,7 @@ public class PlayerOnlineListener implements Listener { this.processors = processors; this.processing = processing; this.serverInfo = serverInfo; + this.dbSystem = dbSystem; this.sessionCache = sessionCache; this.status = status; this.runnableFactory = runnableFactory; @@ -135,6 +140,8 @@ public class PlayerOnlineListener implements Listener { String world = player.getWorld().getName(); String gm = player.getGameMode().name(); + dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), world)); + InetAddress address = player.getAddress().getAddress(); String playerName = player.getName(); diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/WorldChangeListener.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/WorldChangeListener.java index 25637479e..2f8c89af0 100644 --- a/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/WorldChangeListener.java +++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/system/listeners/bukkit/WorldChangeListener.java @@ -17,7 +17,10 @@ package com.djrapitops.plan.system.listeners.bukkit; import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction; import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.settings.config.WorldAliasSettings; import com.djrapitops.plugin.logging.L; import com.djrapitops.plugin.logging.error.ErrorHandler; @@ -34,14 +37,20 @@ import java.util.UUID; public class WorldChangeListener implements Listener { private final WorldAliasSettings worldAliasSettings; + private final ServerInfo serverInfo; + private final DBSystem dbSystem; private final ErrorHandler errorHandler; @Inject public WorldChangeListener( WorldAliasSettings worldAliasSettings, + ServerInfo serverInfo, + DBSystem dbSystem, ErrorHandler errorHandler ) { this.worldAliasSettings = worldAliasSettings; + this.serverInfo = serverInfo; + this.dbSystem = dbSystem; this.errorHandler = errorHandler; } @@ -63,6 +72,7 @@ public class WorldChangeListener implements Listener { String worldName = player.getWorld().getName(); String gameMode = player.getGameMode().name(); + dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), worldName)); worldAliasSettings.addWorld(worldName); Optional cachedSession = SessionCache.getCachedSession(uuid); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/DataStoreQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/DataStoreQueries.java index a32b9ca9e..6926b3715 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/DataStoreQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/db/access/queries/DataStoreQueries.java @@ -19,19 +19,13 @@ package com.djrapitops.plan.db.access.queries; import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.store.keys.SessionKeys; import com.djrapitops.plan.data.time.GMTimes; -import com.djrapitops.plan.data.time.WorldTimes; import com.djrapitops.plan.db.access.ExecBatchStatement; import com.djrapitops.plan.db.access.ExecStatement; import com.djrapitops.plan.db.access.Executable; import com.djrapitops.plan.db.sql.tables.*; -import java.sql.Connection; import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; import java.util.UUID; /** @@ -94,7 +88,6 @@ public class DataStoreQueries { return connection -> { storeSessionInformation(session).execute(connection); storeSessionKills(session).execute(connection); - storeSessionWorldTimesWorlds(session).execute(connection); return storeSessionWorldTimes(session).execute(connection); }; } @@ -123,50 +116,7 @@ public class DataStoreQueries { }; } - // TODO Remove usage after WorldChange event stores world names in its own transaction - private static Executable storeSessionWorldTimesWorlds(Session session) { - return connection -> { - UUID serverUUID = session.getUnsafe(SessionKeys.SERVER_UUID); - - Collection worlds = session.getValue(SessionKeys.WORLD_TIMES) - .map(WorldTimes::getWorldTimes).map(Map::keySet) - .orElse(Collections.emptySet()); - - for (String world : worlds) { - storeWorldName(serverUUID, world).execute(connection); - } - return false; - }; - } - - // TODO Remove usage after WorldChange event stores world names in its own transaction - private static Executable storeWorldName(UUID serverUUID, String worldName) { - return connection -> { - if (!doesWorldNameExist(connection, serverUUID, worldName)) { - return insertWorldName(serverUUID, worldName).execute(connection); - } - return false; - }; - } - - // TODO Remove usage after WorldChange event stores world names in its own transaction - private static boolean doesWorldNameExist(Connection connection, UUID serverUUID, String worldName) { - String selectSQL = "SELECT COUNT(1) as c FROM " + WorldTable.TABLE_NAME + - " WHERE " + WorldTable.NAME + "=?" + - " AND " + WorldTable.SERVER_UUID + "=?"; - try (PreparedStatement statement = connection.prepareStatement(selectSQL)) { - statement.setString(1, worldName); - statement.setString(2, serverUUID.toString()); - try (ResultSet set = statement.executeQuery()) { - return set.next() && set.getInt("c") > 0; - } - } catch (SQLException ignored) { - // Assume it has been saved. - return true; - } - } - - private static Executable insertWorldName(UUID serverUUID, String worldName) { + public static Executable insertWorldName(UUID serverUUID, String worldName) { return new ExecStatement(WorldTable.INSERT_STATEMENT) { @Override public void prepare(PreparedStatement statement) throws SQLException { @@ -177,6 +127,9 @@ public class DataStoreQueries { } private static Executable storeSessionWorldTimes(Session session) { + if (session.getValue(SessionKeys.WORLD_TIMES).map(times -> times.getWorldTimes().isEmpty()).orElse(true)) { + return Executable.empty(); + } return new ExecBatchStatement(WorldTimesTable.INSERT_STATEMENT) { @Override public void prepare(PreparedStatement statement) throws SQLException { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/db/access/transactions/Transaction.java b/Plan/common/src/main/java/com/djrapitops/plan/db/access/transactions/Transaction.java index 105541a2b..176b4c296 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/db/access/transactions/Transaction.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/db/access/transactions/Transaction.java @@ -51,6 +51,8 @@ public abstract class Transaction { Verify.nullCheck(db, () -> new IllegalArgumentException("Given database was null")); Verify.isFalse(success, () -> new IllegalStateException("Transaction has already been executed")); + this.db = db; + if (!shouldBeExecuted()) { return; } @@ -83,7 +85,6 @@ public abstract class Transaction { private void initializeTransaction(SQLDB db) { try { - this.db = db; this.connection = db.getConnection(); // Temporary fix for MySQL Patch task test failing, TODO remove after Auto commit is off for MySQL if (connection.getAutoCommit()) connection.setAutoCommit(false); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/db/access/transactions/events/WorldNameStoreTransaction.java b/Plan/common/src/main/java/com/djrapitops/plan/db/access/transactions/events/WorldNameStoreTransaction.java new file mode 100644 index 000000000..1f8ca3596 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/db/access/transactions/events/WorldNameStoreTransaction.java @@ -0,0 +1,65 @@ +/* + * 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 . + */ +package com.djrapitops.plan.db.access.transactions.events; + +import com.djrapitops.plan.db.access.HasMoreThanZeroQueryStatement; +import com.djrapitops.plan.db.access.queries.DataStoreQueries; +import com.djrapitops.plan.db.access.transactions.Transaction; +import com.djrapitops.plan.db.sql.tables.WorldTable; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.UUID; + +/** + * Transaction to store world name after an event. + * + * @author Rsl1122 + */ +public class WorldNameStoreTransaction extends Transaction { + + private final UUID serverUUID; + private final String worldName; + + public WorldNameStoreTransaction(UUID serverUUID, String worldName) { + this.serverUUID = serverUUID; + this.worldName = worldName; + } + + @Override + protected boolean shouldBeExecuted() { + return doesWorldNameNotExist(); + } + + private boolean doesWorldNameNotExist() { + String sql = "SELECT COUNT(1) as c FROM " + WorldTable.TABLE_NAME + + " WHERE " + WorldTable.NAME + "=?" + + " AND " + WorldTable.SERVER_UUID + "=?"; + return !query(new HasMoreThanZeroQueryStatement(sql) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, worldName); + statement.setString(2, serverUUID.toString()); + } + }); + } + + @Override + protected void performOperations() { + execute(DataStoreQueries.insertWorldName(serverUUID, worldName)); + } +} \ No newline at end of file diff --git a/Plan/common/src/test/java/com/djrapitops/plan/db/CommonDBTest.java b/Plan/common/src/test/java/com/djrapitops/plan/db/CommonDBTest.java index fba6a906e..676d98f2b 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/db/CommonDBTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/db/CommonDBTest.java @@ -34,6 +34,7 @@ import com.djrapitops.plan.db.access.queries.*; import com.djrapitops.plan.db.access.queries.containers.ContainerFetchQueries; import com.djrapitops.plan.db.access.transactions.*; import com.djrapitops.plan.db.access.transactions.events.CommandStoreTransaction; +import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction; import com.djrapitops.plan.db.patches.Patch; import com.djrapitops.plan.db.sql.tables.*; import com.djrapitops.plan.system.PlanSystem; @@ -319,7 +320,10 @@ public abstract class CommonDBTest { gm.put(gms[1], 2000L); gm.put(gms[2], 3000L); gm.put(gms[3], 4000L); - times.put(worlds.get(0), new GMTimes(gm)); + + String worldName = worlds.get(0); + times.put(worldName, new GMTimes(gm)); + db.executeTransaction(new WorldNameStoreTransaction(serverUUID, worldName)); return new WorldTimes(times); } @@ -667,6 +671,7 @@ public abstract class CommonDBTest { "world", GMTimes.getGMKeyArray()[0] ); + db.executeTransaction(new WorldNameStoreTransaction(serverUUID, "world")); session.endSession(System.currentTimeMillis() + 1L); return session; } diff --git a/Plan/common/src/test/java/com/djrapitops/plan/system/webserver/JSErrorRegressionTest.java b/Plan/common/src/test/java/com/djrapitops/plan/system/webserver/JSErrorRegressionTest.java index 917ee1b0a..fa49195ce 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/system/webserver/JSErrorRegressionTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/system/webserver/JSErrorRegressionTest.java @@ -20,6 +20,7 @@ import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.db.Database; import com.djrapitops.plan.db.access.queries.DataStoreQueries; import com.djrapitops.plan.db.access.transactions.Transaction; +import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction; import com.djrapitops.plan.system.PlanSystem; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.settings.config.PlanConfig; @@ -83,12 +84,14 @@ public class JSErrorRegressionTest { database.save().registerNewUser(uuid, 1000L, "TestPlayer"); Session session = new Session(uuid, TestConstants.SERVER_UUID, 1000L, "world", "SURVIVAL"); session.endSession(11000L); + database.executeTransaction(new WorldNameStoreTransaction(TestConstants.SERVER_UUID, "world")); database.executeTransaction(new Transaction() { @Override protected void performOperations() { execute(DataStoreQueries.storeSession(session)); } }); + // TODO Refactor to use Event transactions when available. } diff --git a/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeGMChangeListener.java b/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeGMChangeListener.java index 3315969cb..ec139edb0 100644 --- a/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeGMChangeListener.java +++ b/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeGMChangeListener.java @@ -17,7 +17,10 @@ package com.djrapitops.plan.system.listeners.sponge; import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction; import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.settings.config.WorldAliasSettings; import com.djrapitops.plugin.logging.L; import com.djrapitops.plugin.logging.error.ErrorHandler; @@ -38,14 +41,20 @@ import java.util.UUID; public class SpongeGMChangeListener { private final WorldAliasSettings worldAliasSettings; + private final ServerInfo serverInfo; + private final DBSystem dbSystem; private ErrorHandler errorHandler; @Inject public SpongeGMChangeListener( WorldAliasSettings worldAliasSettings, + ServerInfo serverInfo, + DBSystem dbSystem, ErrorHandler errorHandler ) { this.worldAliasSettings = worldAliasSettings; + this.serverInfo = serverInfo; + this.dbSystem = dbSystem; this.errorHandler = errorHandler; } @@ -70,6 +79,7 @@ public class SpongeGMChangeListener { String gameMode = event.getGameMode().getName().toUpperCase(); String worldName = player.getWorld().getName(); + dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), worldName)); worldAliasSettings.addWorld(worldName); Optional cachedSession = SessionCache.getCachedSession(uuid); diff --git a/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongePlayerListener.java b/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongePlayerListener.java index 87870ca76..092c8b6d2 100644 --- a/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongePlayerListener.java +++ b/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongePlayerListener.java @@ -17,7 +17,9 @@ package com.djrapitops.plan.system.listeners.sponge; import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction; import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.processing.Processing; import com.djrapitops.plan.system.processing.processors.Processors; @@ -55,6 +57,7 @@ public class SpongePlayerListener { private final Processors processors; private final Processing processing; private final ServerInfo serverInfo; + private final DBSystem dbSystem; private SessionCache sessionCache; private final Status status; private RunnableFactory runnableFactory; @@ -66,6 +69,7 @@ public class SpongePlayerListener { Processors processors, Processing processing, ServerInfo serverInfo, + DBSystem dbSystem, SessionCache sessionCache, Status status, RunnableFactory runnableFactory, @@ -75,6 +79,7 @@ public class SpongePlayerListener { this.processors = processors; this.processing = processing; this.serverInfo = serverInfo; + this.dbSystem = dbSystem; this.sessionCache = sessionCache; this.status = status; this.runnableFactory = runnableFactory; @@ -140,6 +145,8 @@ public class SpongePlayerListener { Optional gameMode = player.getGameModeData().get(Keys.GAME_MODE); String gm = gameMode.map(mode -> mode.getName().toUpperCase()).orElse("ADVENTURE"); + dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), world)); + InetAddress address = player.getConnection().getAddress().getAddress(); String playerName = player.getName(); diff --git a/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeWorldChangeListener.java b/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeWorldChangeListener.java index f8460cdc6..78310031c 100644 --- a/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeWorldChangeListener.java +++ b/Plan/sponge/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeWorldChangeListener.java @@ -17,7 +17,10 @@ package com.djrapitops.plan.system.listeners.sponge; import com.djrapitops.plan.data.container.Session; +import com.djrapitops.plan.db.access.transactions.events.WorldNameStoreTransaction; import com.djrapitops.plan.system.cache.SessionCache; +import com.djrapitops.plan.system.database.DBSystem; +import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.settings.config.WorldAliasSettings; import com.djrapitops.plugin.logging.L; import com.djrapitops.plugin.logging.error.ErrorHandler; @@ -41,14 +44,20 @@ import java.util.UUID; public class SpongeWorldChangeListener { private final WorldAliasSettings worldAliasSettings; + private final ServerInfo serverInfo; + private final DBSystem dbSystem; private ErrorHandler errorHandler; @Inject public SpongeWorldChangeListener( WorldAliasSettings worldAliasSettings, + ServerInfo serverInfo, + DBSystem dbSystem, ErrorHandler errorHandler ) { this.worldAliasSettings = worldAliasSettings; + this.serverInfo = serverInfo; + this.dbSystem = dbSystem; this.errorHandler = errorHandler; } @@ -73,6 +82,7 @@ public class SpongeWorldChangeListener { String worldName = event.getToTransform().getExtent().getName(); String gameMode = getGameMode(player); + dbSystem.getDatabase().executeTransaction(new WorldNameStoreTransaction(serverInfo.getServerUUID(), worldName)); worldAliasSettings.addWorld(worldName); Optional cachedSession = SessionCache.getCachedSession(uuid);