From 4dedc10763fcd04ad2106052bc80f25ca1ecce79 Mon Sep 17 00:00:00 2001 From: Ollie <75035364+obfuscatedgenerated@users.noreply.github.com> Date: Sat, 27 May 2023 22:30:41 +0100 Subject: [PATCH] fix a potential memory leak in playerdb --- pom.xml | 2 +- .../java/codes/ollieg/magicmotd/PlayerDB.java | 96 +++++++++++-------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/pom.xml b/pom.xml index 86134b4..80183fd 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ codes.ollieg MagicMOTD - 1.0.2 + 1.0.3 jar MagicMOTD diff --git a/src/main/java/codes/ollieg/magicmotd/PlayerDB.java b/src/main/java/codes/ollieg/magicmotd/PlayerDB.java index 0cadd89..a72d165 100644 --- a/src/main/java/codes/ollieg/magicmotd/PlayerDB.java +++ b/src/main/java/codes/ollieg/magicmotd/PlayerDB.java @@ -20,6 +20,7 @@ public class PlayerDB { /** * Constructs a new {@link PlayerDB}. + * * @param plugin the plugin * @throws IllegalArgumentException if the plugin is null */ @@ -34,7 +35,8 @@ public PlayerDB(@NotNull MagicMOTD plugin) { /** * Creates a connection pool to the database. - * @throws RuntimeException if the H2 database driver cannot be found + * + * @throws RuntimeException if the H2 database driver cannot be found * @throws IllegalStateException if the database is already ready */ public void readyConnections() { @@ -59,6 +61,7 @@ public void readyConnections() { /** * Returns whether the database is ready to be used. + * * @return whether the database is ready */ public boolean isReady() { @@ -67,6 +70,7 @@ public boolean isReady() { /** * Destroys the connection pool. + * * @throws IllegalStateException if the database is not ready */ public void destroyConnections() { @@ -81,8 +85,9 @@ public void destroyConnections() { /** * Creates the database and its table if they don't exist. - * @throws SQLException if an error occurs while creating the database or table - * @throws RuntimeException if the connection fails + * + * @throws SQLException if an error occurs while creating the database or table + * @throws RuntimeException if the connection fails * @throws IllegalStateException if the database is not ready */ public void createIfNotExists() throws SQLException { @@ -108,12 +113,12 @@ public void createIfNotExists() throws SQLException { /** * Updates the player name for the given IP address. * - * @param ip the player's IP address - * @param name the player name - * @throws SQLException if an error occurs while updating the player name + * @param ip the player's IP address + * @param name the player name + * @throws SQLException if an error occurs while updating the player name * @throws IllegalArgumentException if the IP or name is null - * @throws IllegalStateException if the database is not ready - * @throws RuntimeException if the connection fails + * @throws IllegalStateException if the database is not ready + * @throws RuntimeException if the connection fails */ public void setNameForIP(@NotNull String ip, @NotNull String name) throws SQLException { if (ip == null) { @@ -134,16 +139,18 @@ public void setNameForIP(@NotNull String ip, @NotNull String name) throws SQLExc throw new RuntimeException("Connection is null!"); } - PreparedStatement statement = conn.prepareStatement("INSERT INTO PLAYERS (ip, name) VALUES (?, ?) ON DUPLICATE KEY UPDATE name = ?"); - statement.setString(1, ip); - statement.setString(2, name); - statement.setString(3, name); - statement.execute(); + try (PreparedStatement statement = conn.prepareStatement("INSERT INTO PLAYERS (ip, name) VALUES (?, ?) ON DUPLICATE KEY UPDATE name = ?")) { + statement.setString(1, ip); + statement.setString(2, name); + statement.setString(3, name); + statement.execute(); + } } } /** * Returns the player name for the given IP address, or null if the IP address is not in the database. + * * @param ip the player's IP address * @return the player name, or null if the IP address is not in the database */ @@ -161,12 +168,14 @@ public void setNameForIP(@NotNull String ip, @NotNull String name) throws SQLExc throw new RuntimeException("Connection is null!"); } - PreparedStatement statement = conn.prepareStatement("SELECT name FROM PLAYERS WHERE ip = ?"); - statement.setString(1, ip); - ResultSet result = statement.executeQuery(); + try (PreparedStatement statement = conn.prepareStatement("SELECT name FROM PLAYERS WHERE ip = ?")) { + statement.setString(1, ip); - if (result.next()) { - return result.getString("name"); + try (ResultSet result = statement.executeQuery()) { + if (result.next()) { + return result.getString("name"); + } + } } } catch (SQLException e) { throw new RuntimeException(e); @@ -177,11 +186,12 @@ public void setNameForIP(@NotNull String ip, @NotNull String name) throws SQLExc /** * Returns a list of IPs known for the given player name. + * * @param name the player name * @return a list of IPs for the given player name * @throws IllegalArgumentException if the name is null - * @throws IllegalStateException if the database is not ready - * @throws RuntimeException if the connection fails + * @throws IllegalStateException if the database is not ready + * @throws RuntimeException if the connection fails */ public @NotNull List getIPsForName(@NotNull String name) { if (name == null) { @@ -192,22 +202,26 @@ public void setNameForIP(@NotNull String ip, @NotNull String name) throws SQLExc throw new IllegalStateException("Database is not ready!"); } + // TODO: the try-with chaining kinda sucks, perhaps we could encapsulate the process in a method? try (Connection conn = this.pool.getConnection()) { if (conn == null) { throw new RuntimeException("Connection is null!"); } - PreparedStatement statement = conn.prepareStatement("SELECT ip FROM PLAYERS WHERE name = ?"); - statement.setString(1, name); - ResultSet result = statement.executeQuery(); + try (PreparedStatement statement = conn.prepareStatement("SELECT ip FROM PLAYERS WHERE name = ?")) { + statement.setString(1, name); - // convert result set to list - List ips = new ArrayList<>(); - while (result.next()) { - ips.add(result.getString("ip")); - } + try (ResultSet result = statement.executeQuery()) { + + // convert result set to list + List ips = new ArrayList<>(); + while (result.next()) { + ips.add(result.getString("ip")); + } - return ips; + return ips; + } + } } catch (SQLException e) { throw new RuntimeException(e); } @@ -215,10 +229,11 @@ public void setNameForIP(@NotNull String ip, @NotNull String name) throws SQLExc /** * Erases the given IP address from the database. + * * @param ip the IP address to erase * @throws IllegalArgumentException if the IP is null - * @throws IllegalStateException if the database is not ready - * @throws RuntimeException if the connection fails + * @throws IllegalStateException if the database is not ready + * @throws RuntimeException if the connection fails */ public void eraseIP(@NotNull String ip) { if (ip == null) { @@ -234,9 +249,10 @@ public void eraseIP(@NotNull String ip) { throw new RuntimeException("Connection is null!"); } - PreparedStatement statement = conn.prepareStatement("DELETE FROM PLAYERS WHERE ip = ?"); - statement.setString(1, ip); - statement.execute(); + try (PreparedStatement statement = conn.prepareStatement("DELETE FROM PLAYERS WHERE ip = ?")) { + statement.setString(1, ip); + statement.execute(); + } } catch (SQLException e) { throw new RuntimeException(e); } @@ -244,10 +260,11 @@ public void eraseIP(@NotNull String ip) { /** * Erases all records (IP addresses) for the given player name. + * * @param name the player name * @throws IllegalArgumentException if the name is null - * @throws IllegalStateException if the database is not ready - * @throws RuntimeException if the connection fails + * @throws IllegalStateException if the database is not ready + * @throws RuntimeException if the connection fails */ public void eraseName(@NotNull String name) { if (name == null) { @@ -263,9 +280,10 @@ public void eraseName(@NotNull String name) { throw new RuntimeException("Connection is null!"); } - PreparedStatement statement = conn.prepareStatement("DELETE FROM PLAYERS WHERE name = ?"); - statement.setString(1, name); - statement.execute(); + try (PreparedStatement statement = conn.prepareStatement("DELETE FROM PLAYERS WHERE name = ?")) { + statement.setString(1, name); + statement.execute(); + } } catch (SQLException e) { throw new RuntimeException(e); }