Skip to content

Commit 1a7220b

Browse files
committed
Refactor SQLHandler to common
1 parent 0ca8196 commit 1a7220b

File tree

19 files changed

+374
-292
lines changed

19 files changed

+374
-292
lines changed

common/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,13 @@
2323
<maven.compiler.target>21</maven.compiler.target>
2424
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2525
</properties>
26+
27+
<dependencies>
28+
<dependency>
29+
<groupId>com.zaxxer</groupId>
30+
<artifactId>HikariCP</artifactId>
31+
<version>6.3.0</version>
32+
</dependency>
33+
</dependencies>
2634

2735
</project>
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
package com.simplexity.simplepms.common.database;
2+
3+
import com.simplexity.simplepms.common.database.objects.PlayerBlock;
4+
import com.simplexity.simplepms.common.database.objects.PlayerSettings;
5+
import com.simplexity.simplepms.common.logger.Logger;
6+
import com.zaxxer.hikari.HikariConfig;
7+
import com.zaxxer.hikari.HikariDataSource;
8+
9+
import java.sql.*;
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
import java.util.UUID;
13+
14+
public class SQLHandler {
15+
16+
private SQLHandler() { }
17+
18+
private static SQLHandler instance;
19+
private static boolean usingMySQL;
20+
21+
public static SQLHandler getInstance() {
22+
if (instance == null) {
23+
instance = new SQLHandler();
24+
}
25+
return instance;
26+
}
27+
28+
private static HikariDataSource dataSource;
29+
private static final HikariConfig hikariConfig = new HikariConfig();
30+
31+
public void init() {
32+
if (dataSource == null) {
33+
// TODO: Logger error, need to call setupConfig first
34+
return;
35+
}
36+
try (Connection connection = getConnection()) {
37+
PreparedStatement blocklistInitStatement = connection.prepareStatement("""
38+
CREATE TABLE IF NOT EXISTS blocklist (
39+
player_uuid VARCHAR (36) NOT NULL,
40+
blocked_player_uuid VARCHAR(36) NOT NULL,
41+
blocked_player_name VARCHAR(256),
42+
block_reason VARCHAR(256),
43+
PRIMARY KEY (player_uuid, blocked_player_uuid)
44+
);""");
45+
blocklistInitStatement.execute();
46+
PreparedStatement playerSettingsInitStatement = connection.prepareStatement("""
47+
CREATE TABLE IF NOT EXISTS settings (
48+
player_uuid VARCHAR (36) NOT NULL PRIMARY KEY,
49+
socialspy_enabled BOOLEAN NOT NULL,
50+
messages_disabled BOOLEAN NOT NULL
51+
);""");
52+
playerSettingsInitStatement.execute();
53+
updateDatabaseColumns();
54+
} catch (SQLException e) {
55+
Logger.getLogger().warn("Failed to connect to database: {}", e.getMessage(), e);
56+
}
57+
}
58+
59+
public void reloadDatabase(String jdbcUrl, String username, String password) {
60+
Logger.getLogger().info("Reconnecting to SimplePMs database...");
61+
shutdownConnection();
62+
setupConfig(jdbcUrl, username, password);
63+
Logger.getLogger().info("Database reloaded successfully");
64+
}
65+
66+
67+
public PlayerSettings getSettings(UUID playerUUID) {
68+
String queryString = "SELECT socialspy_enabled, messages_disabled FROM settings WHERE player_uuid = ?;";
69+
PlayerSettings settings = null;
70+
try (Connection connection = getConnection()) {
71+
PreparedStatement statement = connection.prepareStatement(queryString);
72+
statement.setString(1, String.valueOf(playerUUID));
73+
try (ResultSet resultSet = statement.executeQuery()) {
74+
if (!resultSet.next()) {
75+
settings = new PlayerSettings(playerUUID);
76+
updateSettings(playerUUID, settings.isSocialSpyEnabled(), settings.areMessagesDisabled());
77+
} else {
78+
boolean socialSpy = resultSet.getBoolean("socialspy_enabled");
79+
boolean messagesDisabled = resultSet.getBoolean("messages_disabled");
80+
settings = new PlayerSettings(playerUUID, socialSpy, messagesDisabled);
81+
}
82+
}
83+
} catch (SQLException e) {
84+
Logger.getLogger().warn("Failed to retrieve settings from database: {}", e.getMessage(), e);
85+
}
86+
return settings;
87+
}
88+
89+
public List<PlayerBlock> getBlockedPlayers(UUID playerUUID) {
90+
String queryString = "SELECT blocked_player_uuid, block_reason, blocked_player_name from blocklist WHERE player_uuid = ?;";
91+
List<PlayerBlock> blockedPlayers = new ArrayList<>();
92+
try (Connection connection = getConnection()) {
93+
PreparedStatement statement = connection.prepareStatement(queryString);
94+
statement.setString(1, String.valueOf(playerUUID));
95+
try (ResultSet resultSet = statement.executeQuery()) {
96+
while (resultSet.next()) {
97+
UUID blockedPlayerUUID = UUID.fromString(resultSet.getString("blocked_player_uuid"));
98+
String blockedPlayerName = resultSet.getString("blocked_player_name");
99+
String reason = resultSet.getString("block_reason");
100+
PlayerBlock block = new PlayerBlock(playerUUID, blockedPlayerName, blockedPlayerUUID, reason);
101+
blockedPlayers.add(block);
102+
}
103+
}
104+
} catch (SQLException e) {
105+
Logger.getLogger().warn("Failed to get blocked players: {}", e.getMessage(), e);
106+
}
107+
return blockedPlayers;
108+
}
109+
110+
public void addBlockedPlayer(UUID playerUUID, UUID blockedPlayerUUID, String blockedPlayerName, String reason) {
111+
String queryString = "REPLACE INTO blocklist (player_uuid, blocked_player_uuid, blocked_player_name, block_reason) VALUES (?, ?, ?, ?);";
112+
try (Connection connection = getConnection()) {
113+
PreparedStatement statement = connection.prepareStatement(queryString);
114+
statement.setString(1, String.valueOf(playerUUID));
115+
statement.setString(2, String.valueOf(blockedPlayerUUID));
116+
statement.setString(3, blockedPlayerName);
117+
statement.setString(4, reason);
118+
statement.executeUpdate();
119+
} catch (SQLException e) {
120+
Logger.getLogger().warn("Failed to add blocked player: {}", e.getMessage(), e);
121+
e.printStackTrace();
122+
}
123+
}
124+
125+
public void removeBlockedPlayer(UUID playerUUID, UUID blockedPlayerUUID) {
126+
String queryString = "DELETE FROM blocklist WHERE player_uuid = ? and blocked_player_uuid = ?;";
127+
try (Connection connection = getConnection()) {
128+
PreparedStatement statement = connection.prepareStatement(queryString);
129+
statement.setString(1, String.valueOf(playerUUID));
130+
statement.setString(2, String.valueOf(blockedPlayerUUID));
131+
statement.executeUpdate();
132+
} catch (SQLException e) {
133+
Logger.getLogger().warn("Failed to remove blocked player: {}", e.getMessage(), e);
134+
}
135+
}
136+
137+
public void updateSettings(UUID playerUUID, boolean socialSpyEnabled, boolean messagesDisabled) {
138+
String queryString = "REPLACE INTO settings (player_uuid, socialspy_enabled, messages_disabled) VALUES (?, ?, ?);";
139+
try (Connection connection = getConnection()) {
140+
PreparedStatement statement = connection.prepareStatement(queryString);
141+
statement.setString(1, String.valueOf(playerUUID));
142+
statement.setBoolean(2, socialSpyEnabled);
143+
statement.setBoolean(3, messagesDisabled);
144+
statement.executeUpdate();
145+
} catch (SQLException e) {
146+
Logger.getLogger().warn("Failed to update settings to database: {}", e.getMessage(), e);
147+
}
148+
149+
}
150+
151+
public void updateDatabaseColumns() {
152+
String tableName = "blocklist";
153+
String columnName = "blocked_player_name";
154+
boolean columnExists;
155+
try {
156+
if (usingMySQL) {
157+
columnExists = doesMysqlColumnExist(tableName, columnName);
158+
} else {
159+
columnExists = doesSqliteColumnExist(tableName, columnName);
160+
}
161+
if (!columnExists) {
162+
addColumn(tableName, columnName, "VARCHAR(256)", "");
163+
}
164+
} catch (Exception e) {
165+
Logger.getLogger().warn("Unable to update database table: {} column: {}, error: {}", tableName, columnName, e.getMessage(), e);
166+
}
167+
}
168+
169+
private Boolean doesSqliteColumnExist(String tableName, String columnName) {
170+
String query = "PRAGMA table_info(" + tableName + ")";
171+
try (Connection connection = getConnection()) {
172+
PreparedStatement statement = connection.prepareStatement(query);
173+
ResultSet resultSet = statement.executeQuery();
174+
while (resultSet.next()) {
175+
if (columnName.equalsIgnoreCase(resultSet.getString("name"))) {
176+
return true;
177+
}
178+
}
179+
} catch (SQLException e) {
180+
Logger.getLogger().warn("Failed to to check for column {} in table {}: {}", columnName, tableName, e.getMessage(), e);
181+
}
182+
return false;
183+
}
184+
185+
private Boolean doesMysqlColumnExist(String tableName, String columnName) {
186+
try (Connection connection = getConnection()) {
187+
DatabaseMetaData metaData = connection.getMetaData();
188+
ResultSet resultSet = metaData.getColumns(null, null, tableName, columnName);
189+
return resultSet.next();
190+
} catch (SQLException e) {
191+
Logger.getLogger().warn("Failed to check for column {} in table {}: {}", columnName, tableName, e.getMessage(), e);
192+
}
193+
return false;
194+
}
195+
196+
// Possibly extremely cursed way to do this :cackle:
197+
198+
public void addColumn(String tableName, String columnName, String dataType, String constraints) {
199+
String query = String.format("ALTER TABLE %s ADD COLUMN %s %s %s;", tableName, columnName, dataType, constraints);
200+
try (Connection connection = getConnection()) {
201+
PreparedStatement statement = connection.prepareStatement(query);
202+
statement.executeUpdate();
203+
Logger.getLogger().info("Added new column '{}' to table '{}'", columnName, tableName);
204+
} catch (SQLException e) {
205+
Logger.getLogger().warn("Failed to add new column {} to table {}: {}", columnName, tableName, e.getMessage(), e);
206+
}
207+
}
208+
209+
private static void loadHikariDataSource() {
210+
if (hikariConfig == null) return; // TODO: Logger for missing hikariConfig
211+
dataSource = new HikariDataSource(hikariConfig);
212+
}
213+
214+
public void setupConfig(String jdbcUrl, String username, String password) {
215+
if (!usingMySQL) {
216+
hikariConfig.setJdbcUrl(jdbcUrl);
217+
hikariConfig.setConnectionTestQuery("PRAGMA journal_mode = WAL;");
218+
loadHikariDataSource();
219+
return;
220+
}
221+
hikariConfig.setJdbcUrl(jdbcUrl);
222+
hikariConfig.setUsername(username);
223+
hikariConfig.setPassword(password);
224+
loadHikariDataSource();
225+
}
226+
227+
public static void setUsingMySQL(boolean usingMySQL) {
228+
SQLHandler.usingMySQL = usingMySQL;
229+
}
230+
231+
public static Connection getConnection() throws SQLException {
232+
return dataSource.getConnection();
233+
}
234+
235+
public void shutdownConnection() {
236+
if (dataSource == null || dataSource.isClosed()) return;
237+
dataSource.close();
238+
dataSource = null;
239+
Logger.getLogger().info("Closed existing database connection");
240+
}
241+
}

paper/src/main/java/simplexity/simplepms/paper/saving/objects/PlayerBlock.java renamed to common/src/main/java/com/simplexity/simplepms/common/database/objects/PlayerBlock.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package simplexity.simplepms.paper.saving.objects;
1+
package com.simplexity.simplepms.common.database.objects;
22

33
import java.util.UUID;
44

paper/src/main/java/simplexity/simplepms/paper/saving/objects/PlayerSettings.java renamed to common/src/main/java/com/simplexity/simplepms/common/database/objects/PlayerSettings.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package simplexity.simplepms.paper.saving.objects;
1+
package com.simplexity.simplepms.common.database.objects;
22

33
import java.util.UUID;
44

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.simplexity.simplepms.common.logger;
2+
3+
import org.slf4j.LoggerFactory;
4+
5+
public class Logger {
6+
7+
private static org.slf4j.Logger logger;
8+
9+
public static org.slf4j.Logger getLogger() {
10+
if (logger == null) logger = LoggerFactory.getLogger("SimplePMs.common");
11+
return logger;
12+
}
13+
14+
public static void setLogger(org.slf4j.Logger logger) {
15+
Logger.logger = logger;
16+
}
17+
18+
}

paper/pom.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,5 @@
109109
<version>2.11.6</version>
110110
<scope>provided</scope>
111111
</dependency>
112-
<dependency>
113-
<groupId>com.zaxxer</groupId>
114-
<artifactId>HikariCP</artifactId>
115-
<version>6.3.0</version>
116-
</dependency>
117112
</dependencies>
118113
</project>

paper/src/main/java/simplexity/simplepms/paper/SimplePMs.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package simplexity.simplepms.paper;
22

3+
import com.simplexity.simplepms.common.logger.Logger;
34
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
45
import net.kyori.adventure.text.minimessage.MiniMessage;
56
import org.bukkit.command.ConsoleCommandSender;
@@ -18,7 +19,7 @@
1819
import simplexity.simplepms.paper.listeners.PreCommandListener;
1920
import simplexity.simplepms.paper.listeners.QuitListener;
2021
import simplexity.simplepms.paper.logic.Constants;
21-
import simplexity.simplepms.paper.saving.SqlHandler;
22+
import simplexity.simplepms.paper.saving.DatabaseHandler;
2223

2324
@SuppressWarnings("UnstableApiUsage")
2425
public final class SimplePMs extends JavaPlugin {
@@ -28,7 +29,6 @@ public final class SimplePMs extends JavaPlugin {
2829
private static boolean papiEnabled = false;
2930
private static ConsoleCommandSender consoleSender;
3031

31-
3232
@Override
3333
public void onEnable() {
3434
instance = this;
@@ -37,10 +37,11 @@ public void onEnable() {
3737
papiEnabled = true;
3838
}
3939
loadConfigStuff();
40-
SqlHandler.getInstance().init();
40+
DatabaseHandler.getInstance().init();
4141
registerListeners();
4242
registerCommands();
4343
registerPermissions();
44+
Logger.setLogger(this.getSLF4JLogger());
4445
}
4546

4647
private void registerListeners() {
@@ -90,7 +91,7 @@ private void registerPermissions() {
9091

9192
@Override
9293
public void onDisable() {
93-
SqlHandler.getInstance().shutdownConnection();
94+
DatabaseHandler.getInstance().shutdownConnection();
9495
}
9596

9697
public static MiniMessage getMiniMessage() {

paper/src/main/java/simplexity/simplepms/paper/commands/Blocklist.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import simplexity.simplepms.paper.config.LocaleMessage;
1313
import simplexity.simplepms.paper.logic.Constants;
1414
import simplexity.simplepms.paper.saving.Cache;
15-
import simplexity.simplepms.paper.saving.objects.PlayerBlock;
15+
import com.simplexity.simplepms.common.database.objects.PlayerBlock;
1616

1717
import java.util.List;
1818
import java.util.UUID;

paper/src/main/java/simplexity/simplepms/paper/commands/MessageToggle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import simplexity.simplepms.paper.config.LocaleMessage;
99
import simplexity.simplepms.paper.logic.Constants;
1010
import simplexity.simplepms.paper.saving.Cache;
11-
import simplexity.simplepms.paper.saving.objects.PlayerSettings;
11+
import com.simplexity.simplepms.common.database.objects.PlayerSettings;
1212

1313
import java.util.UUID;
1414

paper/src/main/java/simplexity/simplepms/paper/commands/Reload.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import simplexity.simplepms.paper.config.ConfigHandler;
99
import simplexity.simplepms.paper.config.LocaleMessage;
1010
import simplexity.simplepms.paper.logic.Constants;
11-
import simplexity.simplepms.paper.saving.SqlHandler;
11+
import simplexity.simplepms.paper.saving.DatabaseHandler;
1212

1313
@SuppressWarnings("UnstableApiUsage")
1414
public class Reload {
@@ -19,7 +19,7 @@ public static LiteralCommandNode<CommandSourceStack> createCommand() {
1919
.executes(ctx -> {
2020
CommandSender sender = ctx.getSource().getSender();
2121
ConfigHandler.getInstance().loadConfigValues();
22-
SqlHandler.getInstance().reloadDatabase();
22+
DatabaseHandler.getInstance().reloadDatabase();
2323
sender.sendRichMessage(LocaleMessage.RELOADED.getMessage());
2424
return Command.SINGLE_SUCCESS;
2525
}).build();

0 commit comments

Comments
 (0)