Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-78 Rewrite database to ORMLite JDBC #116

Merged
merged 46 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
4c8c2e5
Start working on new database system
Jakubk15 Oct 26, 2024
0810f48
Add ParcelWrapper class, add ORMLite repository implementation
Jakubk15 Oct 29, 2024
57bcd61
Fix immutable list modification, apply codestyle changes
Jakubk15 Oct 30, 2024
ed59bd6
Implement Locker ORMLite repository
Jakubk15 Oct 30, 2024
fbeb6b3
Add ItemStorage ORMLite repository implementation
Jakubk15 Oct 30, 2024
69288e0
Add User ORMLite implementation
Jakubk15 Oct 30, 2024
b13613c
Add ParcelContent ORMLite implementation
Jakubk15 Oct 30, 2024
953942a
Use CompletableFuture#runAsync instead of scheduler one. Delete legac…
Jakubk15 Nov 15, 2024
d8b5f02
Set more DatabaseManager properties
Jakubk15 Nov 15, 2024
fdc6f1f
Merge remote-tracking branch 'origin/master' into ormlite-jdbc
Jakubk15 Dec 26, 2024
4504529
Fix integration tests
Jakubk15 Dec 26, 2024
ad6b908
Update TODO
Jakubk15 Dec 26, 2024
76e592e
Update version in Gradle
Jakubk15 Dec 26, 2024
ea901ee
Fix cache and rename getInstance to getSingleton in persister classes
Jakubk15 Dec 26, 2024
d99c514
Bump spigot-api to 1.21.4
Jakubk15 Dec 31, 2024
f433141
Disable ORMLite logs
Jakubk15 Dec 31, 2024
f708327
Tick TODO
Jakubk15 Dec 31, 2024
500ad40
Apply suggestion
Jakubk15 Dec 31, 2024
7bb711d
Apply CodeRabbit suggestion regarding remove() method in ParcelReposi…
Jakubk15 Dec 31, 2024
8b26340
Add TestScheduler
Jakubk15 Dec 31, 2024
3fd2eb3
Revert "Use CompletableFuture#runAsync instead of scheduler one.
Jakubk15 Dec 31, 2024
405ceed
Use ConcurrentHashMaps in caches
Jakubk15 Dec 31, 2024
6868080
Fix unit tests build
Jakubk15 Dec 31, 2024
0c700be
Update src/main/java/com/eternalcode/parcellockers/database/DatabaseM…
Jakubk15 Dec 31, 2024
cd38904
Revert version check
Jakubk15 Dec 31, 2024
ed5a455
Update src/main/java/com/eternalcode/parcellockers/locker/repository/…
Jakubk15 Dec 31, 2024
e3c74f1
Merge remote-tracking branch 'origin/ormlite-jdbc' into ormlite-jdbc
Jakubk15 Dec 31, 2024
1137be0
Correct order of CRUD operations
Jakubk15 Dec 31, 2024
7ddc481
Correct isAsync method
Jakubk15 Dec 31, 2024
602d353
Make locker positions unique
Jakubk15 Dec 31, 2024
93ef8e4
Rename warp to entity
Jakubk15 Jan 10, 2025
8c5959b
Update MC version in artifact name
Jakubk15 Jan 10, 2025
e62bcd6
Apply Rollczi's suggestions
Jakubk15 Jan 14, 2025
441acd6
Update src/test/java/com/eternalcode/parcellockers/TestScheduler.java
Jakubk15 Jan 14, 2025
ca5922e
Refactor caching system
Jakubk15 Jan 14, 2025
0507635
Merge branch 'ormlite-jdbc' of https://github.com/EternalCodeTeam/Par…
Jakubk15 Jan 14, 2025
d62297e
Update src/main/java/com/eternalcode/parcellockers/parcel/repository/…
Jakubk15 Jan 15, 2025
b7be250
Update src/main/java/com/eternalcode/parcellockers/parcel/repository/…
Jakubk15 Jan 15, 2025
ecd70af
Update src/main/java/com/eternalcode/parcellockers/ParcelLockers.java
Jakubk15 Jan 15, 2025
90b5f11
Update src/main/java/com/eternalcode/parcellockers/database/persister…
Jakubk15 Jan 15, 2025
1eef1e4
Update src/main/java/com/eternalcode/parcellockers/database/persister…
Jakubk15 Jan 15, 2025
cee39bc
Update src/main/java/com/eternalcode/parcellockers/content/repository…
Jakubk15 Jan 15, 2025
025a95b
Apply CodeRabbit suggestions
Jakubk15 Jan 15, 2025
defdc12
Fix build
Jakubk15 Jan 15, 2025
4619bcc
Fail-fast if table creation does not succeed
Jakubk15 Jan 15, 2025
7e978f0
[ci skip] Assign databaseManager field
Jakubk15 Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
## 📝 TODO

- [ ] Add support for more databases (H2, PostgreSQL, MongoDB?)
- [x] Add support for more databases (H2, PostgreSQL, MongoDB?)
- [ ] Add translation system, more languages
- [ ] Add delivery codes, so any person knowing the code can pick up the parcel
- [ ] Add delivery time, so the parcel can be picked up only in a specific time
- [ ] Parcel permissions for user
- [ ] Parcel return logic
- [x] Banned parcel items (configurable)
- [ ] Parcel fee
- [ ] Rewrite database to ORMLite (far in future)
- [x] Rewrite database to ORMLite (far in future)
- [ ] Add more parcel types (fragile, etc...)
- [ ] Add option to config for parcel locker space (e.g. max parcels within a locker)
- [ ] Finish GUIs
Expand Down
11 changes: 7 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ repositories {

dependencies {
// minecraft development api
compileOnly("org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT")
compileOnly("org.spigotmc:spigot-api:1.21.4-R0.1-SNAPSHOT")
implementation("net.kyori:adventure-platform-bukkit:4.3.4")
implementation("net.kyori:adventure-text-minimessage:4.18.0")
implementation("dev.rollczi:litecommands-bukkit:3.9.5")
Expand Down Expand Up @@ -57,6 +57,9 @@ dependencies {

// database
implementation("com.zaxxer:HikariCP:6.2.1")
implementation("com.j256.ormlite:ormlite-jdbc:6.1")
implementation("com.h2database:h2:2.3.232")
implementation("org.postgresql:postgresql:42.7.4")
Jakubk15 marked this conversation as resolved.
Show resolved Hide resolved

// lombok
compileOnly("org.projectlombok:lombok:1.18.36")
Expand Down Expand Up @@ -122,20 +125,20 @@ tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
options.setIncremental(true)
options.compilerArgs.add("-parameters")
options.release = 17
options.release = 21
}

tasks {
runServer {
minecraftVersion("1.21.1")
minecraftVersion("1.21.4")
}

test {
useJUnitPlatform()
}

shadowJar {
archiveFileName.set("ParcelLockers v${project.version} (MC 1.8.8-1.21.x).jar")
archiveFileName.set("ParcelLockers v${project.version} (MC 1.21.3-1.21.4).jar")

exclude(
"org/intellij/lang/annotations/**",
Expand Down
71 changes: 50 additions & 21 deletions src/main/java/com/eternalcode/parcellockers/ParcelLockers.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,43 @@

import com.eternalcode.commons.adventure.AdventureLegacyColorPostProcessor;
import com.eternalcode.commons.adventure.AdventureLegacyColorPreProcessor;
import com.eternalcode.commons.bukkit.scheduler.BukkitSchedulerImpl;
import com.eternalcode.commons.scheduler.Scheduler;
import com.eternalcode.parcellockers.command.handler.InvalidUsageImpl;
import com.eternalcode.parcellockers.command.handler.PermissionMessage;
import com.eternalcode.parcellockers.configuration.ConfigurationManager;
import com.eternalcode.parcellockers.configuration.implementation.PluginConfiguration;
import com.eternalcode.parcellockers.content.repository.ParcelContentRepository;
import com.eternalcode.parcellockers.content.repository.ParcelContentRepositoryImpl;
import com.eternalcode.parcellockers.database.DataSourceFactory;
import com.eternalcode.parcellockers.content.repository.ParcelContentRepositoryOrmLite;
import com.eternalcode.parcellockers.database.DatabaseManager;
import com.eternalcode.parcellockers.gui.implementation.locker.LockerMainGUI;
import com.eternalcode.parcellockers.gui.implementation.remote.MainGUI;
import com.eternalcode.parcellockers.gui.implementation.remote.ParcelListGUI;
import com.eternalcode.parcellockers.itemstorage.repository.ItemStorageRepository;
import com.eternalcode.parcellockers.itemstorage.repository.ItemStorageRepositoryImpl;
import com.eternalcode.parcellockers.itemstorage.repository.ItemStorageRepositoryOrmLite;
import com.eternalcode.parcellockers.locker.Locker;
import com.eternalcode.parcellockers.locker.argument.ParcelLockerArgument;
import com.eternalcode.parcellockers.locker.controller.LockerBreakController;
import com.eternalcode.parcellockers.locker.controller.LockerInteractionController;
import com.eternalcode.parcellockers.locker.controller.LockerPlaceController;
import com.eternalcode.parcellockers.locker.repository.LockerRepositoryImpl;
import com.eternalcode.parcellockers.locker.repository.LockerCache;
import com.eternalcode.parcellockers.locker.repository.LockerRepositoryOrmLite;
import com.eternalcode.parcellockers.notification.NotificationAnnouncer;
import com.eternalcode.parcellockers.parcel.Parcel;
import com.eternalcode.parcellockers.parcel.ParcelManager;
import com.eternalcode.parcellockers.parcel.command.ParcelCommand;
import com.eternalcode.parcellockers.parcel.command.argument.ParcelArgument;
import com.eternalcode.parcellockers.parcel.command.argument.ParcelLockerArgument;
import com.eternalcode.parcellockers.parcel.repository.ParcelRepository;
import com.eternalcode.parcellockers.parcel.repository.ParcelRepositoryImpl;
import com.eternalcode.parcellockers.parcel.repository.ParcelCache;
import com.eternalcode.parcellockers.parcel.repository.ParcelRepositoryOrmLite;
import com.eternalcode.parcellockers.updater.UpdaterService;
import com.eternalcode.parcellockers.user.LoadUserController;
import com.eternalcode.parcellockers.user.PrepareUserController;
import com.eternalcode.parcellockers.user.UserManager;
import com.eternalcode.parcellockers.user.UserRepository;
import com.eternalcode.parcellockers.user.UserRepositoryImpl;
import com.eternalcode.parcellockers.user.repository.UserRepository;
import com.eternalcode.parcellockers.user.repository.UserRepositoryOrmLite;
import com.google.common.base.Stopwatch;
import com.zaxxer.hikari.HikariDataSource;
import com.j256.ormlite.logger.LoggerFactory;
import com.j256.ormlite.logger.NullLogBackend;
import dev.rollczi.litecommands.LiteCommands;
import dev.rollczi.litecommands.adventure.LiteAdventureExtension;
import dev.rollczi.litecommands.annotations.LiteCommandsAnnotations;
Expand All @@ -54,6 +58,7 @@
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;

import java.sql.SQLException;
import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
Expand All @@ -71,6 +76,8 @@ public final class ParcelLockers extends JavaPlugin {

private Economy economy;

private DatabaseManager databaseManager;

@Override
public void onEnable() {
Stopwatch started = Stopwatch.createStarted();
Expand All @@ -87,6 +94,7 @@ public void onEnable() {
ConfigurationManager configManager = new ConfigurationManager(this.getDataFolder());
PluginConfiguration config = configManager.load(new PluginConfiguration());
Server server = this.getServer();
Scheduler scheduler = new BukkitSchedulerImpl(this);

if (config.settings.enableSentry) {
Sentry.init(options -> {
Expand All @@ -97,37 +105,54 @@ public void onEnable() {
options.setTag("serverVersion", this.getServer().getVersion());
options.setTag("serverSoftware", PaperLib.getEnvironment().getName());
options.setTag("plugins", Arrays.stream(server.getPluginManager().getPlugins()).toList().toString());
options.setEnabled(false);
Jakubk15 marked this conversation as resolved.
Show resolved Hide resolved
this.getLogger().info("Sentry initialized successfully!");
});
}

HikariDataSource dataSource = DataSourceFactory.buildHikariDataSource(config, this.getDataFolder());
LoggerFactory.setLogBackendFactory(new NullLogBackend.NullLogBackendFactory());

DatabaseManager databaseManager = new DatabaseManager(config, this.getLogger(), this.getDataFolder());
Jakubk15 marked this conversation as resolved.
Show resolved Hide resolved
this.databaseManager = databaseManager;

try {
databaseManager.connect();
}
catch (SQLException exception) {
this.getLogger().severe("Could not connect to database! Some functions may not work properly!");
throw new RuntimeException(exception);
}

this.skullAPI = LiteSkullFactory.builder()
.cacheExpireAfterWrite(Duration.ofMinutes(45L))
.bukkitScheduler(this)
.threadPool(20)
.build();

LockerRepositoryImpl lockerRepository = new LockerRepositoryImpl(dataSource);
LockerCache lockerCache = new LockerCache();
ParcelCache parcelCache = new ParcelCache();

LockerRepositoryOrmLite lockerRepository = new LockerRepositoryOrmLite(databaseManager, scheduler, lockerCache);
lockerRepository.updateCaches();
ItemStorageRepository itemStorageRepository = new ItemStorageRepositoryImpl(dataSource);

ParcelRepository parcelRepository = new ParcelRepositoryImpl(dataSource);
ParcelRepositoryOrmLite parcelRepository = new ParcelRepositoryOrmLite(databaseManager, scheduler, parcelCache);
parcelRepository.updateCaches();

ParcelManager parcelManager = new ParcelManager(config, announcer, parcelRepository);

UserRepository userRepository = new UserRepositoryImpl(dataSource);
ItemStorageRepository itemStorageRepository = new ItemStorageRepositoryOrmLite(databaseManager, scheduler);

UserRepository userRepository = new UserRepositoryOrmLite(databaseManager, scheduler);
UserManager userManager = new UserManager(userRepository);

ParcelContentRepository parcelContentRepository = new ParcelContentRepositoryImpl(dataSource);
ParcelContentRepository parcelContentRepository = new ParcelContentRepositoryOrmLite(databaseManager, scheduler);

MainGUI mainGUI = new MainGUI(this, server, miniMessage, config, parcelRepository, lockerRepository, userManager);
ParcelListGUI parcelListGUI = new ParcelListGUI(this, server, miniMessage, config, parcelRepository, lockerRepository, userManager, mainGUI);

this.liteCommands = LiteBukkitFactory.builder("parcellockers", this)
.argument(Parcel.class, new ParcelArgument(parcelRepository))
.argument(Locker.class, new ParcelLockerArgument(lockerRepository))
.argument(Parcel.class, new ParcelArgument(parcelCache))
.argument(Locker.class, new ParcelLockerArgument(lockerCache))
.extension(new LiteAdventureExtension<>())
.message(LiteBukkitMessages.PLAYER_ONLY, config.messages.onlyForPlayers)
.commands(LiteCommandsAnnotations.of(
Expand All @@ -147,9 +172,9 @@ public void onEnable() {
LockerMainGUI lockerMainGUI = new LockerMainGUI(this, miniMessage, config, itemStorageRepository, parcelRepository, lockerRepository, announcer, parcelContentRepository, userRepository, this.skullAPI);

Stream.of(
new LockerInteractionController(lockerRepository, lockerMainGUI),
new LockerInteractionController(lockerCache, lockerMainGUI),
new LockerPlaceController(config, this, lockerRepository, announcer),
new LockerBreakController(lockerRepository, announcer, config.messages),
new LockerBreakController(lockerRepository, lockerCache, announcer, config.messages),
new PrepareUserController(userManager),
new LoadUserController(userManager, server)
).forEach(controller -> server.getPluginManager().registerEvents(controller, this));
Expand All @@ -163,6 +188,10 @@ public void onEnable() {

@Override
public void onDisable() {
if (this.databaseManager != null) {
this.databaseManager.disconnect();
}

if (this.liteCommands != null) {
this.liteCommands.unregister();
}
Expand All @@ -181,7 +210,7 @@ private void softwareCheck() {
if (!environment.isPaper()) {
logger.warning("Your server running on unsupported software, please use Paper or its forks");
logger.warning("You can easily download Paper from https://papermc.io/downloads");
logger.warning("WARNING: Supported MC versions are 1.17.x-1.19.x");
logger.warning("WARNING: Supported MC versions are 1.17.x-1.21.x");
Jakubk15 marked this conversation as resolved.
Show resolved Hide resolved
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ public interface ParcelContentRepository {

CompletableFuture<Void> save(ParcelContent parcelContent);

CompletableFuture<Void> remove(UUID uniqueId);

CompletableFuture<Void> update(ParcelContent parcelContent);
CompletableFuture<Integer> remove(UUID uniqueId);

CompletableFuture<Optional<ParcelContent>> find(UUID uniqueId);

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.eternalcode.parcellockers.content.repository;

import com.eternalcode.commons.scheduler.Scheduler;
import com.eternalcode.parcellockers.content.ParcelContent;
import com.eternalcode.parcellockers.database.DatabaseManager;
import com.eternalcode.parcellockers.database.wrapper.AbstractRepositoryOrmLite;
import com.j256.ormlite.table.TableUtils;
import io.sentry.Sentry;

import java.sql.SQLException;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

public class ParcelContentRepositoryOrmLite extends AbstractRepositoryOrmLite implements ParcelContentRepository {

public ParcelContentRepositoryOrmLite(DatabaseManager databaseManager, Scheduler scheduler) {
super(databaseManager, scheduler);

try {
TableUtils.createTableIfNotExists(databaseManager.connectionSource(), ParcelContentWrapper.class);
} catch (SQLException exception) {
Sentry.captureException(exception);
throw new RuntimeException("Failed to create ParcelContent table", exception);
}
}

@Override
public CompletableFuture<Void> save(ParcelContent parcelContent) {
Jakubk15 marked this conversation as resolved.
Show resolved Hide resolved
return this.saveIfNotExist(ParcelContentWrapper.class, ParcelContentWrapper.from(parcelContent)).thenApply(dao -> null);
}

@Override
public CompletableFuture<Integer> remove(UUID uniqueId) {
return this.deleteById(ParcelContentWrapper.class, uniqueId);
}

@Override
public CompletableFuture<Optional<ParcelContent>> find(UUID uniqueId) {
return this.select(ParcelContentWrapper.class, uniqueId).thenApply(parcelContentWrapper -> Optional.ofNullable(parcelContentWrapper.toParcelContent()));
}
Jakubk15 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.eternalcode.parcellockers.content.repository;

import com.eternalcode.parcellockers.content.ParcelContent;
import com.eternalcode.parcellockers.database.persister.ItemStackPersister;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.bukkit.inventory.ItemStack;

import java.util.List;
import java.util.UUID;

@DatabaseTable(tableName = "parcel_content")
class ParcelContentWrapper {

@DatabaseField(id = true)
private UUID uniqueId;

@DatabaseField(persisterClass = ItemStackPersister.class)
private List<ItemStack> content;

ParcelContentWrapper() {
}

ParcelContentWrapper(UUID uniqueId, List<ItemStack> content) {
this.uniqueId = uniqueId;
this.content = content;
}
Jakubk15 marked this conversation as resolved.
Show resolved Hide resolved

static ParcelContentWrapper from(ParcelContent parcelContent) {
return new ParcelContentWrapper(parcelContent.uniqueId(), parcelContent.items());
}

ParcelContent toParcelContent() {
return new ParcelContent(this.uniqueId, this.content);
}
Jakubk15 marked this conversation as resolved.
Show resolved Hide resolved
}
Loading