From cd8f1a183fdeaf5d0f6346ad0ba64182a07af166 Mon Sep 17 00:00:00 2001 From: RaftDev Date: Sat, 30 Dec 2023 04:03:20 +0100 Subject: [PATCH] Async Modules --- .../network/api/AtlasNetworkServer.java | 6 +- .../atlasworld/network/api/NetworkModule.java | 114 +++++------ .../atlasworld/network/api/module/Module.java | 47 +---- ...nContext.java => ModuleUnloadContext.java} | 2 +- .../network/api/test/TestModule.java | 50 +---- .../api/test/command/MyTestCommand.java | 19 -- .../api/test/command/TestCommands.java | 23 --- .../test/configuration/TestConfiguration.java | 15 -- .../TestConfigurationSchema.java | 33 ---- .../api/test/event/NetworkListener.java | 17 -- .../api/test/event/ServerListener.java | 14 -- .../api/test/networking/TestPackets.java | 14 -- .../networking/packets/MyCustomPacket.java | 50 ----- .../test/services/database/LocalDatabase.java | 184 ------------------ .../database/LocalDatabaseService.java | 92 --------- .../services/database/LocalDatabaseStore.java | 81 -------- .../atlasworld/network/core/AtlasNetwork.java | 54 ++--- .../core/module/SystemModuleManager.java | 44 +++-- .../loader/SystemModuleClassLoader.java | 6 +- .../provider/factory/FileModuleFactory.java | 5 +- .../provider/factory/ModuleFactory.java | 2 +- .../core/module/store/ModuleEntryStore.java | 15 +- .../core/services/SystemServiceManager.java | 1 - 23 files changed, 119 insertions(+), 769 deletions(-) rename api/src/main/java/fr/atlasworld/network/api/module/lifecycle/{ModuleDeactivationContext.java => ModuleUnloadContext.java} (82%) delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/command/MyTestCommand.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/command/TestCommands.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/configuration/TestConfiguration.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/configuration/TestConfigurationSchema.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/event/NetworkListener.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/event/ServerListener.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/networking/TestPackets.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/networking/packets/MyCustomPacket.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabase.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabaseService.java delete mode 100644 api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabaseStore.java diff --git a/api/src/main/java/fr/atlasworld/network/api/AtlasNetworkServer.java b/api/src/main/java/fr/atlasworld/network/api/AtlasNetworkServer.java index 9c485d5..4cb71d7 100644 --- a/api/src/main/java/fr/atlasworld/network/api/AtlasNetworkServer.java +++ b/api/src/main/java/fr/atlasworld/network/api/AtlasNetworkServer.java @@ -75,7 +75,7 @@ public interface AtlasNetworkServer { * @return future action to notify your code when your task finishes, of fails. */ @CanIgnoreReturnValue - FutureAction createAsyncSupplier(Module module, Supplier supplier); + FutureAction createAsyncSupplier(Supplier supplier); /** * Creates an asynchronous task using the system's Executor Pool. @@ -84,7 +84,7 @@ public interface AtlasNetworkServer { * @return future action to notify your code when your task finishes, or fails. */ @CanIgnoreReturnValue - FutureAction createAsyncTask(Module module, Runnable runnable); + FutureAction createAsyncTask(Runnable runnable); /** * Creates an asynchronous task that will run every specified time interval. @@ -95,5 +95,5 @@ public interface AtlasNetworkServer { * @return future action, this action will never successfully complete, it can only fail or be cancelled. */ @CanIgnoreReturnValue - FutureAction createSequenceTask(Module module, Runnable runnable, long interval, TimeUnit intervalUnit); + FutureAction createSequenceTask(Runnable runnable, long interval, TimeUnit intervalUnit); } diff --git a/api/src/main/java/fr/atlasworld/network/api/NetworkModule.java b/api/src/main/java/fr/atlasworld/network/api/NetworkModule.java index f905893..6405cc7 100644 --- a/api/src/main/java/fr/atlasworld/network/api/NetworkModule.java +++ b/api/src/main/java/fr/atlasworld/network/api/NetworkModule.java @@ -6,8 +6,8 @@ import fr.atlasworld.network.api.module.Module; import fr.atlasworld.network.api.module.ModuleMeta; import fr.atlasworld.network.api.module.ModuleStatus; -import fr.atlasworld.network.api.module.lifecycle.ModuleActivationContext; -import fr.atlasworld.network.api.module.lifecycle.ModuleDeactivationContext; +import fr.atlasworld.network.api.module.exception.unchecked.ExecutionModuleException; +import fr.atlasworld.network.api.module.lifecycle.ModuleUnloadContext; import fr.atlasworld.network.api.module.lifecycle.ModuleLoadContext; import fr.atlasworld.network.api.util.archive.JarArchive; import org.jetbrains.annotations.ApiStatus; @@ -19,6 +19,8 @@ import java.io.InputStream; import java.io.Reader; import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.jar.JarEntry; /** @@ -26,14 +28,16 @@ * It provides basic functionality for initializing, activating, deactivating, and managing the module's lifecycle. */ public abstract class NetworkModule implements Module { + private final BlockingQueue operationQueue = new LinkedBlockingQueue<>(); + private ModuleMeta meta = null; private File file = null; private JarArchive archive = null; private ModuleClassLoader classLoader = null; private ModuleStatus status = ModuleStatus.INACTIVE; private Logger logger = null; - private boolean loaded = false; - private SimpleFutureAction deactivationFuture; + private boolean running = false; + private Thread thread; @ApiStatus.Internal public NetworkModule() { @@ -45,25 +49,22 @@ public NetworkModule() { } /** - * This method is called before your module activates, - * use this if you need to load specific classes or files before your module activates. + * Your module code starts here, Register your listeners here. *

- * WARNING: The system is far from being fully initialized. So use this with caution. + * WARNING: The system is far from being fully initialized. + * Many of the operation are not yet available. + * So don't start logic that interacts with the {@link AtlasNetworkServer} in this method. + * @param ctx load context. */ - @Override - public void onLoad(@NotNull ModuleLoadContext ctx) { + protected void onLoad(@NotNull ModuleLoadContext ctx) { } /** - * Override this method, your module code starts here. + * Called when the system is shutting down, + * gracefully shutdown your module when this method is called. + * @param ctx unload context. */ - protected void onActivate(@NotNull ModuleActivationContext ctx) { - } - - /** - * Called when the system is shutting down - */ - protected void onDeactivate(@NotNull ModuleDeactivationContext ctx) { + protected void onUnload(@NotNull ModuleUnloadContext ctx) { } @NotNull @@ -87,15 +88,9 @@ public final File getFile() { return this.classLoader; } - @NotNull - @Override - public final ModuleStatus getStatus() { - return this.status; - } - @ApiStatus.Internal - public final void initialize(@NotNull ModuleMeta meta, @NotNull File file, @NotNull JarArchive archive, @NotNull ModuleClassLoader classLoader, @NotNull Logger logger) { - if (this.loaded) + public final void initialize(@NotNull ModuleMeta meta, @NotNull File file, @NotNull JarArchive archive, @NotNull ModuleClassLoader classLoader, @NotNull Logger logger, ModuleLoadContext ctx) throws ExecutionModuleException { + if (this.running) throw new UnsupportedOperationException("Module has already been initialized!"); this.meta = meta; @@ -103,51 +98,56 @@ public final void initialize(@NotNull ModuleMeta meta, @NotNull File file, @NotN this.archive = archive; this.classLoader = classLoader; this.logger = logger; - - this.loaded = true; - - this.deactivationFuture = new SimpleFutureAction<>(); } - @Override @ApiStatus.Internal - public final void activate(@NotNull ModuleActivationContext ctx) { - if (this.status == ModuleStatus.ACTIVE) - throw new IllegalStateException("Module is already activated!"); - - if (this.deactivationFuture.isDone()) - this.deactivationFuture = new SimpleFutureAction<>(); + public final void start(ModuleLoadContext ctx) { + this.thread = Thread.currentThread(); + this.running = true; + + try { + this.onLoad(ctx); + } catch (Throwable throwable) { + throw new ExecutionModuleException(throwable); + } - this.status = ModuleStatus.ACTIVE; - this.onActivate(ctx); - } + while(this.running) { + try { + Runnable task = this.operationQueue.take(); - @Override - @ApiStatus.Internal - public final void deactivate(@NotNull ModuleDeactivationContext ctx) { - if (this.status != ModuleStatus.ACTIVE) - throw new IllegalStateException("Module is already deactivated!"); + task.run(); + } catch (InterruptedException ignored) { - this.status = ModuleStatus.INACTIVE; - this.onDeactivate(ctx); - this.deactivationFuture.complete(null); // Trigger success listeners. - } - - @Override - @ApiStatus.Internal - public final void crash(Throwable throwable) { - this.status = ModuleStatus.CRASHED; - this.logger.error("Oh no! I just crashed!", throwable); - this.deactivationFuture.fail(throwable); // Trigger failed listeners. + } catch (Throwable cause) { + this.logger.warn("Could not execute module task:", cause); + } + } } public final Logger getLogger() { return this.logger; } + @NotNull + @Override + public Thread getThread() { + return this.thread; + } + @Override - public final FutureAction deactivationFuture() { - return this.deactivationFuture; + public FutureAction execute(Runnable runnable) { + SimpleFutureAction future = new SimpleFutureAction<>(); + + this.operationQueue.add(() -> { + try { + runnable.run(); + future.complete(null); + } catch (Throwable throwable) { + future.fail(throwable); + } + }); + + return future; } @Override diff --git a/api/src/main/java/fr/atlasworld/network/api/module/Module.java b/api/src/main/java/fr/atlasworld/network/api/module/Module.java index 7c009c5..7d2b133 100644 --- a/api/src/main/java/fr/atlasworld/network/api/module/Module.java +++ b/api/src/main/java/fr/atlasworld/network/api/module/Module.java @@ -1,11 +1,7 @@ package fr.atlasworld.network.api.module; import fr.atlasworld.network.api.concurrent.action.FutureAction; -import fr.atlasworld.network.api.module.lifecycle.ModuleActivationContext; -import fr.atlasworld.network.api.module.lifecycle.ModuleDeactivationContext; -import fr.atlasworld.network.api.module.lifecycle.ModuleLoadContext; import fr.atlasworld.network.api.util.archive.Archive; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -16,7 +12,7 @@ public interface Module extends Archive { /** - * Retrieve the configured meta information of the module. + * Retrieve the configured meta-information of the module. */ @NotNull ModuleMeta getMeta(); @@ -31,44 +27,13 @@ public interface Module extends Archive { @NotNull ClassLoader getClassLoader(); /** - * Retrieve the module status. + * Retrieve the thread running this module. */ - @NotNull ModuleStatus getStatus(); + @NotNull Thread getThread(); /** - * Called when the module has been loaded, - * but before it has been set in an active state. - *

- * Call {@link #onLoad(ModuleLoadContext)} before calling {@link #activate(ModuleActivationContext)} + * Execute a task on the module thread. + * @param runnable task to execute. */ - void onLoad(@NotNull ModuleLoadContext ctx); - - /** - * Called when the module is set into an active state. - */ - @ApiStatus.Internal - void activate(@NotNull ModuleActivationContext ctx); - - /** - * Called when the module is set into an inactive state. - */ - @ApiStatus.Internal - void deactivate(@NotNull ModuleDeactivationContext ctx); - - /** - * Called when an uncaught exception was caught on the module. - * - * @param throwable cause - */ - @ApiStatus.Internal - void crash(Throwable throwable); - - /** - * Retrieve the deactivation future of the module. - * Success listeners are called when the module deactivates normally. - * Fail listeners are called when the module crashes. - * - * @return null if the module is not yet activated. - */ - FutureAction deactivationFuture(); + FutureAction execute(Runnable runnable); } diff --git a/api/src/main/java/fr/atlasworld/network/api/module/lifecycle/ModuleDeactivationContext.java b/api/src/main/java/fr/atlasworld/network/api/module/lifecycle/ModuleUnloadContext.java similarity index 82% rename from api/src/main/java/fr/atlasworld/network/api/module/lifecycle/ModuleDeactivationContext.java rename to api/src/main/java/fr/atlasworld/network/api/module/lifecycle/ModuleUnloadContext.java index 42f0feb..e2bf4fa 100644 --- a/api/src/main/java/fr/atlasworld/network/api/module/lifecycle/ModuleDeactivationContext.java +++ b/api/src/main/java/fr/atlasworld/network/api/module/lifecycle/ModuleUnloadContext.java @@ -5,6 +5,6 @@ /** * Lifecycle context for when a module deactivates. */ -public interface ModuleDeactivationContext { +public interface ModuleUnloadContext { AtlasNetworkServer getServer(); } diff --git a/api/src/test/java/fr/atlasworld/network/api/test/TestModule.java b/api/src/test/java/fr/atlasworld/network/api/test/TestModule.java index 5b07f44..82f79cc 100644 --- a/api/src/test/java/fr/atlasworld/network/api/test/TestModule.java +++ b/api/src/test/java/fr/atlasworld/network/api/test/TestModule.java @@ -1,59 +1,17 @@ package fr.atlasworld.network.api.test; import fr.atlasworld.network.api.NetworkModule; -import fr.atlasworld.network.api.file.FileManager; -import fr.atlasworld.network.api.file.configuration.ConfigurationReader; -import fr.atlasworld.network.api.module.Module; -import fr.atlasworld.network.api.module.lifecycle.ModuleActivationContext; -import fr.atlasworld.network.api.module.lifecycle.ModuleDeactivationContext; import fr.atlasworld.network.api.module.lifecycle.ModuleLoadContext; -import fr.atlasworld.network.api.services.database.DatabaseService; -import fr.atlasworld.network.api.test.command.TestCommands; -import fr.atlasworld.network.api.test.configuration.TestConfiguration; -import fr.atlasworld.network.api.test.configuration.TestConfigurationSchema; -import fr.atlasworld.network.api.test.event.NetworkListener; -import fr.atlasworld.network.api.test.event.ServerListener; -import fr.atlasworld.network.api.test.services.database.LocalDatabaseService; import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; public class TestModule extends NetworkModule { - public static Logger LOGGER; - public static Module MODULE; @Override public void onLoad(@NotNull ModuleLoadContext ctx) { - ctx.getModuleClassLoader().useLibraryClassPath(true); // Makes sure the libraries can be used. - ctx.getModuleClassLoader().allowExternalClasspathUsage(false); // Test Module classes may only be used by itself. + try { + Thread.sleep(3000); + } catch (InterruptedException e) {} - LOGGER = this.getLogger(); - MODULE = this; - - LOGGER.info("Registering services.."); - ctx.getServer().getServiceManager().registerService(this, DatabaseService.class, new LocalDatabaseService()); - } - - @Override - protected void onActivate(@NotNull ModuleActivationContext ctx) { - LOGGER.info("Module activated!"); - - FileManager fileManager = ctx.getServer().getFileManager(); - - ctx.getServer().getModuleManager().registerListener(this, new ServerListener()); - ctx.getServer().getModuleManager().registerListener(this, new NetworkListener()); - ctx.getServer().getModuleManager().registerListener(this, new TestCommands()); - - ConfigurationReader testConfReader = - fileManager.registerConfiguration(new TestConfigurationSchema()); - - TestConfiguration configuration = testConfReader.readElseDefault(); // We try to read the file. - if (configuration.isPrintConsole()) { - LOGGER.info("Configuration file said I can say it here!"); - } - } - - @Override - protected void onDeactivate(@NotNull ModuleDeactivationContext ctx) { - LOGGER.info("Module deactivated!"); + this.getLogger().info("I'm running on my own freaking thread ({})! Yeah baby!", getThread()); } } diff --git a/api/src/test/java/fr/atlasworld/network/api/test/command/MyTestCommand.java b/api/src/test/java/fr/atlasworld/network/api/test/command/MyTestCommand.java deleted file mode 100644 index c53c76d..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/command/MyTestCommand.java +++ /dev/null @@ -1,19 +0,0 @@ -package fr.atlasworld.network.api.test.command; - -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import fr.atlasworld.network.api.command.Command; -import fr.atlasworld.network.api.command.CommandSource; - -public final class MyTestCommand { - public static Command create() { - return new Command<>( - LiteralArgumentBuilder.literal("myTestCommand") - .executes(ctx -> execute(ctx.getSource())) - ); - } - - private static int execute(CommandSource source) { - source.sendMessage("You executed the Test Module test command!"); - return Command.SINGLE_SUCCESS; - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/command/TestCommands.java b/api/src/test/java/fr/atlasworld/network/api/test/command/TestCommands.java deleted file mode 100644 index 0303560..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/command/TestCommands.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.atlasworld.network.api.test.command; - -import fr.atlasworld.network.api.command.Command; -import fr.atlasworld.network.api.command.CommandSource; -import fr.atlasworld.network.api.command.event.CommandRegistrationEvent; -import fr.atlasworld.network.api.event.EventHandler; -import fr.atlasworld.network.api.event.EventListener; -import fr.atlasworld.network.api.registry.Register; -import fr.atlasworld.network.api.registry.RegistryObject; -import fr.atlasworld.network.api.test.TestModule; - -public class TestCommands implements EventListener { - private static final Register> COMMANDS = new Register<>(TestModule.MODULE); - - public static final RegistryObject> MY_TEST_COMMAND = COMMANDS.register("my_test_command", - MyTestCommand::create); - - @EventHandler - private void register(CommandRegistrationEvent event) { - COMMANDS.register(event); - TestModule.LOGGER.info("Commands Registered."); - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/configuration/TestConfiguration.java b/api/src/test/java/fr/atlasworld/network/api/test/configuration/TestConfiguration.java deleted file mode 100644 index 4a22533..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/configuration/TestConfiguration.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.atlasworld.network.api.test.configuration; - -import fr.atlasworld.network.api.file.configuration.ConfigurationFile; - -public class TestConfiguration implements ConfigurationFile { - private final boolean printConsole; - - public TestConfiguration(boolean printConsole) { - this.printConsole = printConsole; - } - - public boolean isPrintConsole() { - return printConsole; - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/configuration/TestConfigurationSchema.java b/api/src/test/java/fr/atlasworld/network/api/test/configuration/TestConfigurationSchema.java deleted file mode 100644 index f963aa9..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/configuration/TestConfigurationSchema.java +++ /dev/null @@ -1,33 +0,0 @@ -package fr.atlasworld.network.api.test.configuration; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import fr.atlasworld.network.api.file.configuration.ConfigurationSchema; -import org.jetbrains.annotations.NotNull; - -public class TestConfigurationSchema implements ConfigurationSchema { - @Override - public @NotNull String filepath() { - return "test_dir/test"; - } - - @Override - public int configurationVersion() { - return 1; - } - - @Override - public @NotNull TestConfiguration defaultConfiguration() { - return new TestConfiguration(true); - } - - @Override - public @NotNull Class configurationClass() { - return TestConfiguration.class; - } - - @Override - public @NotNull TestConfiguration updateConfiguration(JsonElement json, Gson gson, int currentVersion) { - return gson.fromJson(json, this.configurationClass()); - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/event/NetworkListener.java b/api/src/test/java/fr/atlasworld/network/api/test/event/NetworkListener.java deleted file mode 100644 index f5402a9..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/event/NetworkListener.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.atlasworld.network.api.test.event; - -import fr.atlasworld.network.api.event.EventHandler; -import fr.atlasworld.network.api.event.EventListener; -import fr.atlasworld.network.api.networking.HandshakeInformation; -import fr.atlasworld.network.api.networking.event.HandshakeDataInjectionEvent; -import fr.atlasworld.network.api.test.TestModule; - -public class NetworkListener implements EventListener { - - @EventHandler - private void onHandshake(HandshakeDataInjectionEvent event) { - event.inject("my_unique_id", HandshakeInformation.text("my_custom_info")); - - TestModule.LOGGER.info("Successfully injected handshake data."); - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/event/ServerListener.java b/api/src/test/java/fr/atlasworld/network/api/test/event/ServerListener.java deleted file mode 100644 index 8da4e15..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/event/ServerListener.java +++ /dev/null @@ -1,14 +0,0 @@ -package fr.atlasworld.network.api.test.event; - -import fr.atlasworld.network.api.event.EventHandler; -import fr.atlasworld.network.api.event.EventListener; -import fr.atlasworld.network.api.server.event.SystemServerStartedEvent; -import fr.atlasworld.network.api.test.TestModule; - -public class ServerListener implements EventListener { - - @EventHandler - private void onServerStarted(SystemServerStartedEvent event) { - TestModule.LOGGER.info("(Auto-Detected) Server took {}ms to boot up.", event.getTotalBootTime()); - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/networking/TestPackets.java b/api/src/test/java/fr/atlasworld/network/api/test/networking/TestPackets.java deleted file mode 100644 index f973673..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/networking/TestPackets.java +++ /dev/null @@ -1,14 +0,0 @@ -package fr.atlasworld.network.api.test.networking; - -import fr.atlasworld.network.api.networking.packet.NetworkPacket; -import fr.atlasworld.network.api.registry.Register; -import fr.atlasworld.network.api.registry.RegistryObject; -import fr.atlasworld.network.api.test.TestModule; -import fr.atlasworld.network.api.test.networking.packets.MyCustomPacket; - -public class TestPackets { - private static final Register PACKETS = new Register<>(TestModule.MODULE); - - public static final RegistryObject MY_CUSTOM_PACKET = PACKETS.register("my_custom_packet", - MyCustomPacket::new); -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/networking/packets/MyCustomPacket.java b/api/src/test/java/fr/atlasworld/network/api/test/networking/packets/MyCustomPacket.java deleted file mode 100644 index 768f444..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/networking/packets/MyCustomPacket.java +++ /dev/null @@ -1,50 +0,0 @@ -package fr.atlasworld.network.api.test.networking.packets; - -import fr.atlasworld.network.api.networking.ConnectionSource; -import fr.atlasworld.network.api.networking.exception.packet.PacketExecutionException; -import fr.atlasworld.network.api.networking.packet.NetworkPacket; -import fr.atlasworld.network.api.networking.packet.PacketByteBuf; -import org.jetbrains.annotations.NotNull; - -public class MyCustomPacket implements NetworkPacket { - - private int myInt; - private String myString; - private boolean myBoolean; - - public MyCustomPacket() { - - } - - public MyCustomPacket(int myInt, String myString, boolean myBoolean) { - this.myInt = myInt; - this.myString = myString; - this.myBoolean = myBoolean; - } - - @Override - public void decode(@NotNull ConnectionSource source, @NotNull PacketByteBuf buffer) throws PacketExecutionException { - this.myInt = buffer.readInt(); - this.myString = buffer.readString(); - this.myBoolean = buffer.readBoolean(); - } - - @Override - public void encode(@NotNull PacketByteBuf buffer) throws PacketExecutionException { - buffer.writeInt(this.myInt); - buffer.writeString(buffer.readString()); - buffer.writeBoolean(buffer.readBoolean()); - } - - public int getMyInt() { - return myInt; - } - - public String getMyString() { - return myString; - } - - public boolean isMyBoolean() { - return myBoolean; - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabase.java b/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabase.java deleted file mode 100644 index f676aec..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabase.java +++ /dev/null @@ -1,184 +0,0 @@ -package fr.atlasworld.network.api.test.services.database; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import fr.atlasworld.network.api.concurrent.action.FutureAction; -import fr.atlasworld.network.api.concurrent.action.SimpleFutureAction; -import fr.atlasworld.network.api.file.reader.JsonFileReader; -import fr.atlasworld.network.api.services.database.Database; -import fr.atlasworld.network.api.services.database.DatabaseEntity; -import fr.atlasworld.network.api.services.database.DatabaseEntityFactory; -import fr.atlasworld.network.api.services.database.exceptions.DatabaseConnectionClosedException; -import fr.atlasworld.network.api.services.database.exceptions.DatabaseDataTransformationException; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.concurrent.ThreadSafe; -import java.io.IOException; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.stream.Stream; - -@ThreadSafe -public class LocalDatabase implements Database { - private final BlockingQueue queue; - private final JsonFileReader reader; - private final LocalDatabaseService parent; - private final DatabaseEntityFactory factory; - private final Gson gson; - - private JsonObject json; - - public LocalDatabase(BlockingQueue queue, JsonFileReader reader, LocalDatabaseService parent, DatabaseEntityFactory factory, Gson gson) { - this.queue = queue; - this.reader = reader; - this.parent = parent; - this.factory = factory; - this.gson = gson; - } - - public void update() { - for (Runnable task : this.queue) { - try { - task.run(); - } catch (Throwable ignored) { - this.queue.add(task); - } - } - } - - private void ensureCacheLoaded() throws IOException { - if (this.json == null) { - if (!this.reader.exists()) { - this.reader.create(); - this.reader.write(new JsonObject()); - } - - this.json = this.reader.read(); - } - } - - private void save() throws IOException { - this.reader.write(this.json); - } - - @Override - public FutureAction save(@NotNull E data) { - SimpleFutureAction action = new SimpleFutureAction<>(); - - this.queue.add(() -> { - try { - if (this.parent.closed()) - throw new DatabaseConnectionClosedException("Database connection closed."); - - LocalDatabaseStore store = new LocalDatabaseStore(new JsonObject(), this.gson); - this.factory.toDatabase(store, data); - - this.ensureCacheLoaded(); - - JsonObject dataJson = store.getJson(); - this.json.add(data.id(), dataJson); - - this.save(); - - action.complete(null); - } catch (Exception e) { // Only get checked exceptions. - action.fail(e); - } - }); - - return action; - } - - @Override - public FutureAction> load(@NotNull String id) { - SimpleFutureAction> action = new SimpleFutureAction<>(); - - this.queue.add(() -> { - try { - if (this.parent.closed()) - throw new DatabaseConnectionClosedException("Database connection closed."); - - this.ensureCacheLoaded(); - - if (!this.json.has(id)) { - action.complete(Optional.empty()); - return; - } - - JsonObject jsonData = this.json.get(id).getAsJsonObject(); - LocalDatabaseStore store = new LocalDatabaseStore(jsonData, this.gson); - E data = this.factory.create(store, id); - - action.complete(Optional.of(data)); - } catch (Exception e) { // Only get checked exceptions - action.fail(e); - } - }); - - return action; - } - - @Override - public FutureAction delete(@NotNull String id) { - SimpleFutureAction action = new SimpleFutureAction<>(); - - this.queue.add(() -> { - try { - if (this.parent.closed()) - throw new DatabaseConnectionClosedException("Database connection closed."); - - this.ensureCacheLoaded(); - - if (this.json.has(id)) - this.json.remove(id); - - this.save(); - - action.complete(null); - } catch (Exception e) { // Only get checked exceptions - action.fail(e); - } - }); - - return action; - } - - @Override - public FutureAction> stream() { - SimpleFutureAction> action = new SimpleFutureAction<>(); - - this.queue.add(() -> { - try { - if (this.parent.closed()) - throw new DatabaseConnectionClosedException("Database connection closed."); - - this.ensureCacheLoaded(); - - Set collection = new HashSet<>(); - for (Map.Entry entry : this.json.entrySet()) { - LocalDatabaseStore store = new LocalDatabaseStore(entry.getValue().getAsJsonObject(), this.gson); - - try { - collection.add(this.factory.create(store, entry.getKey())); - } catch (DatabaseDataTransformationException ignored) { - } // Simply do not add the element to the collections if it could not be parsed. - } - - action.complete(collection.stream()); - } catch (Exception e) { // Only get check exceptions - action.fail(e); - } - }); - - return action; - } - - @Override - public void clearCache() { - this.queue.add(() -> this.json = null); - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabaseService.java b/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabaseService.java deleted file mode 100644 index 2613fd2..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabaseService.java +++ /dev/null @@ -1,92 +0,0 @@ -package fr.atlasworld.network.api.test.services.database; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import fr.atlasworld.network.api.AtlasNetwork; -import fr.atlasworld.network.api.concurrent.action.FutureAction; -import fr.atlasworld.network.api.file.reader.JsonFileReader; -import fr.atlasworld.network.api.services.database.Database; -import fr.atlasworld.network.api.services.database.DatabaseEntity; -import fr.atlasworld.network.api.services.database.DatabaseEntityFactory; -import fr.atlasworld.network.api.services.database.DatabaseService; -import fr.atlasworld.network.api.services.database.exceptions.DatabaseConnectionClosedException; -import fr.atlasworld.network.api.services.database.exceptions.DatabaseDataTransformationException; -import fr.atlasworld.network.api.services.database.exceptions.DatabaseException; -import fr.atlasworld.network.api.test.TestModule; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -public class LocalDatabaseService implements DatabaseService { - private static final File DATABASE_DIRECTORY = new File( - AtlasNetwork.getServer().getFileManager().getModuleDataDirectory(TestModule.MODULE), - "database" - ); - - private final Map> createdDatabases = new ConcurrentHashMap<>(); - private final Gson gson = new Gson(); - - private FutureAction action; - private boolean closed; - - public LocalDatabaseService() { - this.closed = true; - } - - @Override - public void connect() throws DatabaseException { - if (!this.closed) - throw new DatabaseException("Already connected to the database."); - - this.action = AtlasNetwork.getServer().createSequenceTask(TestModule.MODULE, () -> { - for (LocalDatabase database : this.createdDatabases.values()) { - database.update(); - } - }, 100, TimeUnit.MILLISECONDS); - - this.closed = false; - TestModule.LOGGER.info("Database Service started."); - } - - @Override - public void close() throws DatabaseException { - if (this.closed) - throw new DatabaseConnectionClosedException("Connection with database is already closed."); - - this.action.cancel(false); - this.action = null; - - this.closed = true; - } - - @Override - public boolean closed() { - return this.closed; - } - - @Override - @SuppressWarnings("unchecked") - public Database getDatabase(@NotNull String name, @NotNull DatabaseEntityFactory factory) throws DatabaseException { - if (this.closed) - throw new DatabaseConnectionClosedException("Connection with the database has been closed."); - - if (this.createdDatabases.containsKey(name)) { - try { - return (LocalDatabase) this.createdDatabases.get(name); - } catch (ClassCastException e) { - throw new DatabaseDataTransformationException("Registered database type does not support provided type."); - } - } - - JsonFileReader reader = new JsonFileReader<>(new File(DATABASE_DIRECTORY, name + ".json"), StandardCharsets.UTF_8, this.gson, JsonObject.class); - LocalDatabase database = new LocalDatabase<>(new ArrayBlockingQueue<>(Integer.MAX_VALUE), reader, this, factory, this.gson); - - this.createdDatabases.put(name, database); - return database; - } -} diff --git a/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabaseStore.java b/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabaseStore.java deleted file mode 100644 index f9b830d..0000000 --- a/api/src/test/java/fr/atlasworld/network/api/test/services/database/LocalDatabaseStore.java +++ /dev/null @@ -1,81 +0,0 @@ -package fr.atlasworld.network.api.test.services.database; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import fr.atlasworld.network.api.services.database.DatabaseStore; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Type; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class LocalDatabaseStore implements DatabaseStore { - private final JsonObject json; - private final Gson gson; - - public LocalDatabaseStore(JsonObject json, Gson gson) { - this.json = json; - this.gson = gson; - } - - @Override - public void put(@NotNull String key, @NotNull Object data) { - this.json.add(key, this.gson.toJsonTree(data)); - this.json.addProperty(key + "_type", data.getClass().getName()); - } - - @Override - public boolean has(@NotNull String key) { - return this.json.has(key); - } - - @Override - @Nullable - public T get(@NotNull String key, @NotNull Type type) { - if (!this.json.has(key)) - return null; - - return this.gson.fromJson(this.json.get(key), type); - } - - @Nullable - private Class getType(@NotNull String key) { - try { - String typeName = this.json.get(key + "_type").getAsString(); - return this.getClass().getClassLoader().loadClass(typeName); - } catch (Throwable throwable) { - return null; - } - } - - @Override - public Stream> stream() { - return this.json.asMap() - .entrySet() - .stream() - .map(entry -> { - Class type = this.getType(entry.getKey()); - - if (type == null) - return null; - - Object obj = this.gson.fromJson(entry.getValue(), type); - return Map.entry(entry.getKey(), obj); - }) - .filter(Objects::nonNull); - } - - @Override - public Map asMap() { - return this.stream().collect(Collectors.toMap( - Map.Entry::getKey, - Map.Entry::getValue)); - } - - public JsonObject getJson() { - return json; - } -} diff --git a/src/main/java/fr/atlasworld/network/core/AtlasNetwork.java b/src/main/java/fr/atlasworld/network/core/AtlasNetwork.java index 94c4a93..a49005c 100644 --- a/src/main/java/fr/atlasworld/network/core/AtlasNetwork.java +++ b/src/main/java/fr/atlasworld/network/core/AtlasNetwork.java @@ -10,7 +10,7 @@ import fr.atlasworld.network.api.module.ModuleMeta; import fr.atlasworld.network.api.module.ModuleStatus; import fr.atlasworld.network.api.module.lifecycle.ModuleActivationContext; -import fr.atlasworld.network.api.module.lifecycle.ModuleDeactivationContext; +import fr.atlasworld.network.api.module.lifecycle.ModuleUnloadContext; import fr.atlasworld.network.api.module.lifecycle.ModuleLoadContext; import fr.atlasworld.network.api.security.SecurityManager; import fr.atlasworld.network.api.AtlasNetworkServer; @@ -94,15 +94,13 @@ public static AtlasNetwork getInstance() { public void start() { LOGGER.info("Loading AtlasNetwork.."); - SystemModuleManager.INSTANCE.load(); // Load Modules + SystemModuleManager.INSTANCE.loadModules(this); // Load Modules SystemServerManager.load(this); LOGGER.info("Initializing AtlasNetwork.."); SystemServerManager.init(); - SystemModuleManager.INSTANCE.initialize(); // Initialize Modules - // Events Listener SystemModuleManager.INSTANCE.registerListener(this, new Commands()); @@ -183,24 +181,18 @@ public SystemSocket getSocket() { } @Override - public FutureAction createAsyncSupplier(Module module, Supplier supplier) { - SimpleFutureAction action = ActionUtilities.supply(supplier); - module.deactivationFuture().whenDone((v, cause) -> action.cancel(cause != null)); // Interrupt if the module crashed. - return action; + public FutureAction createAsyncSupplier(Supplier supplier) { + return ActionUtilities.supply(supplier); } @Override - public FutureAction createAsyncTask(Module module, Runnable runnable) { - SimpleFutureAction action = ActionUtilities.execute(runnable); - module.deactivationFuture().whenDone((v, cause) -> action.cancel(cause != null)); // Interrupt if the module crashed. - return action; + public FutureAction createAsyncTask(Runnable runnable) { + return ActionUtilities.execute(runnable); } @Override - public FutureAction createSequenceTask(Module module, Runnable runnable, long interval, TimeUnit intervalUnit) { - SimpleFutureAction action = ActionUtilities.sequential(runnable, interval, intervalUnit); - module.deactivationFuture().whenDone((v, cause) -> action.cancel(cause != null)); // Interrupt if the module crashed. - return action; + public FutureAction createSequenceTask(Runnable runnable, long interval, TimeUnit intervalUnit) { + return ActionUtilities.sequential(runnable, interval, intervalUnit); } @Override @@ -258,7 +250,7 @@ public String[] getContributors() { @Override public @NotNull String mainClass() { - return "ya.sorry.no.start.point"; + return "fr.atlasworld.network.core.AtlasNetwork"; } @Override @@ -279,32 +271,12 @@ public URL[] modulesLibraries() { } @Override - public @NotNull ModuleStatus getStatus() { - return ModuleStatus.ACTIVE; - } - - @Override - public void onLoad(@NotNull ModuleLoadContext ctx) { - throw new UnsupportedOperationException("Core module can not handle lifecycle events."); - } - - @Override - public void activate(@NotNull ModuleActivationContext ctx) { - throw new UnsupportedOperationException("Core module can not handle lifecycle events."); - } - - @Override - public void deactivate(@NotNull ModuleDeactivationContext ctx) { - throw new UnsupportedOperationException("Core module can not handle lifecycle events."); - } - - @Override - public void crash(Throwable throwable) { - Bootstrap.crash(throwable); + public @NotNull Thread getThread() { + throw new UnsupportedOperationException("AtlasNetwork Core Module is running on the system main thread."); } @Override - public FutureAction deactivationFuture() { - return null; + public FutureAction execute(Runnable runnable) { + return this.createAsyncTask(runnable); } } diff --git a/src/main/java/fr/atlasworld/network/core/module/SystemModuleManager.java b/src/main/java/fr/atlasworld/network/core/module/SystemModuleManager.java index 703312d..1f872b7 100644 --- a/src/main/java/fr/atlasworld/network/core/module/SystemModuleManager.java +++ b/src/main/java/fr/atlasworld/network/core/module/SystemModuleManager.java @@ -1,17 +1,21 @@ package fr.atlasworld.network.core.module; import com.google.common.base.Preconditions; +import fr.atlasworld.network.api.AtlasNetworkServer; import fr.atlasworld.network.api.event.CancellableEvent; import fr.atlasworld.network.api.event.Event; import fr.atlasworld.network.api.event.EventHandler; import fr.atlasworld.network.api.event.EventListener; import fr.atlasworld.network.api.module.Module; import fr.atlasworld.network.api.module.ModuleManager; +import fr.atlasworld.network.api.module.exception.unchecked.ExecutionModuleException; +import fr.atlasworld.network.api.module.lifecycle.ModuleLoadContext; import fr.atlasworld.network.core.AtlasNetwork; import fr.atlasworld.network.core.boot.LaunchArgs; import fr.atlasworld.network.core.logging.LogUtils; import fr.atlasworld.network.core.module.event.EventListenerStore; -import fr.atlasworld.network.core.module.lifecycle.ModuleActivateContextImpl; +import fr.atlasworld.network.core.module.lifecycle.ModuleLoadContextImpl; +import fr.atlasworld.network.core.module.loader.SystemModuleClassLoader; import fr.atlasworld.network.core.module.store.DirectoryModuleSourceStore; import fr.atlasworld.network.core.module.store.FlagModuleSourceStore; import fr.atlasworld.network.core.module.store.ModuleEntryStore; @@ -25,6 +29,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class SystemModuleManager implements ModuleManager { private static final Logger LOGGER = LogUtils.getLogger(); @@ -34,6 +40,8 @@ public class SystemModuleManager implements ModuleManager { private final Map, List> registeredListeners; private final ModuleEntryStore holder; + private ExecutorService moduleThreadPool; + private SystemModuleManager() { this.registeredSourceHolders = new ArrayList<>(); this.registeredListeners = new ConcurrentHashMap<>(); @@ -61,35 +69,33 @@ public static SystemModuleManager init(LaunchArgs args) { return moduleManager; } - public void load() { + public void loadModules(AtlasNetworkServer server) { LOGGER.info("Loading modules.."); if (this.registeredSourceHolders.isEmpty()) throw new IllegalStateException("No module source we're registered."); long startTime = System.currentTimeMillis(); - this.registeredSourceHolders.forEach(source -> source.load(this.holder)); - this.holder.loadModules(); // Load Modules and call onLoaded method. + this.registeredSourceHolders.forEach(source -> source.load(this.holder)); // Load Modules from source to memory. + this.holder.loadModules(); // Load + + this.moduleThreadPool = Executors.newFixedThreadPool(this.holder.getLoadedModules().size()); + + this.holder.getLoadedModules().forEach(module -> { + this.moduleThreadPool.submit(() -> { + try { + module.start(new ModuleLoadContextImpl((SystemModuleClassLoader) module.getClassLoader(), server)); + } catch (ExecutionModuleException e) { + LOGGER.error("Could not start module '{}'!", module.getMeta().getId(), e); + } + }); + }); long calculatedLoadingTime = (System.currentTimeMillis() - startTime); if (calculatedLoadingTime > 1000) { LOGGER.warn("Modules loading took longer than 1000ms! Time: {}ms.", calculatedLoadingTime); } else { - LOGGER.info("Loaded {} module(s) in {}ms.", holder.getLoadedModules().size(), calculatedLoadingTime); - } - } - - public void initialize() { - LOGGER.info("Initializing modules.."); - - long startTime = System.currentTimeMillis(); - this.holder.activeModules(new ModuleActivateContextImpl(AtlasNetwork.getInstance())); - - long calculatedActivationTime = (System.currentTimeMillis() - startTime); - if (calculatedActivationTime > 10000) { - LOGGER.warn("Modules activation took longer than 10000ms! Time: {}ms.", calculatedActivationTime); - } else { - LOGGER.info("Activated {} module(s) in {}ms.", holder.getLoadedModules().size(), calculatedActivationTime); + LOGGER.info("Loaded {} module(s) in {}ms.", this.holder.getLoadedModules().size(), calculatedLoadingTime); } } diff --git a/src/main/java/fr/atlasworld/network/core/module/loader/SystemModuleClassLoader.java b/src/main/java/fr/atlasworld/network/core/module/loader/SystemModuleClassLoader.java index ab4966d..83fa1b1 100644 --- a/src/main/java/fr/atlasworld/network/core/module/loader/SystemModuleClassLoader.java +++ b/src/main/java/fr/atlasworld/network/core/module/loader/SystemModuleClassLoader.java @@ -4,7 +4,10 @@ import fr.atlasworld.network.api.loader.GroupClassLoader; import fr.atlasworld.network.api.loader.ModuleClassLoader; import fr.atlasworld.network.api.module.ModuleMeta; +import fr.atlasworld.network.api.module.lifecycle.ModuleLoadContext; import fr.atlasworld.network.api.util.archive.JarArchive; +import fr.atlasworld.network.core.AtlasNetwork; +import fr.atlasworld.network.core.module.lifecycle.ModuleLoadContextImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -121,8 +124,9 @@ public void init(@NotNull NetworkModule module) { throw new UnsupportedOperationException("ModuleClassLoader has already been initialized!"); this.module = module; + ModuleLoadContext context = new ModuleLoadContextImpl(this, AtlasNetwork.getInstance()); - module.initialize(this.configuration, this.moduleFile, this.moduleArchive, this, this.logger); + module.initialize(this.configuration, this.moduleFile, this.moduleArchive, this, this.logger, context); } @Override diff --git a/src/main/java/fr/atlasworld/network/core/module/provider/factory/FileModuleFactory.java b/src/main/java/fr/atlasworld/network/core/module/provider/factory/FileModuleFactory.java index 21ddc03..5a8010c 100644 --- a/src/main/java/fr/atlasworld/network/core/module/provider/factory/FileModuleFactory.java +++ b/src/main/java/fr/atlasworld/network/core/module/provider/factory/FileModuleFactory.java @@ -133,10 +133,7 @@ public NetworkModule create() { throw new IllegalStateException(main.getName() + " must extend the " + NetworkModule.class.getName() + " class!"); } - NetworkModule module = (NetworkModule) main.getDeclaredConstructor().newInstance(); - module.onLoad(new ModuleLoadContextImpl(loader, AtlasNetwork.getInstance())); - - return module; + return (NetworkModule) main.getDeclaredConstructor().newInstance(); } catch (Throwable e) { throw new UncheckedModuleException(new InvalidModuleException(this.meta, e)); } diff --git a/src/main/java/fr/atlasworld/network/core/module/provider/factory/ModuleFactory.java b/src/main/java/fr/atlasworld/network/core/module/provider/factory/ModuleFactory.java index 3ce4433..0ab76aa 100644 --- a/src/main/java/fr/atlasworld/network/core/module/provider/factory/ModuleFactory.java +++ b/src/main/java/fr/atlasworld/network/core/module/provider/factory/ModuleFactory.java @@ -36,7 +36,7 @@ public interface ModuleFactory { ClassLoader getClassLoader(); /** - * Creates the network module, this will also call {@link Module#onLoad(ModuleLoadContext)} on the module + * Creates the network module. */ NetworkModule create(); } diff --git a/src/main/java/fr/atlasworld/network/core/module/store/ModuleEntryStore.java b/src/main/java/fr/atlasworld/network/core/module/store/ModuleEntryStore.java index 54e6249..c2816dc 100644 --- a/src/main/java/fr/atlasworld/network/core/module/store/ModuleEntryStore.java +++ b/src/main/java/fr/atlasworld/network/core/module/store/ModuleEntryStore.java @@ -12,6 +12,7 @@ import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; /** * Holds all loaded modules @@ -40,17 +41,6 @@ public void loadModules() { this.savedPools.values().forEach(pool -> this.loadedModules.addAll(pool.create())); } - public void activeModules(ModuleActivationContext ctx) { - for (NetworkModule module : this.loadedModules) { - try { - module.activate(ctx); - } catch (Throwable throwable) { - this.loadedModules.remove(module); - module.crash(throwable); - } - } - } - public Set getLoadedModules() { return ImmutableSet.copyOf(this.loadedModules); } @@ -62,8 +52,9 @@ public NetworkModule getModule(String id) { .findFirst().orElse(null); } - public static class ModuleEntryHolderPool { + public static final class ModuleEntryHolderPool { private final Map savedFactories = new ConcurrentHashMap<>(); + private ExecutorService threadPool; private ModuleEntryHolderPool() { } // Only parent class is allowed to create pools diff --git a/src/main/java/fr/atlasworld/network/core/services/SystemServiceManager.java b/src/main/java/fr/atlasworld/network/core/services/SystemServiceManager.java index ded67cd..ac074e8 100644 --- a/src/main/java/fr/atlasworld/network/core/services/SystemServiceManager.java +++ b/src/main/java/fr/atlasworld/network/core/services/SystemServiceManager.java @@ -23,7 +23,6 @@ public SystemServiceManager() { @Override public void registerService(Module module, Class serviceClass, T serviceImpl) { this.registeredServices.put(serviceClass, serviceImpl); - module.deactivationFuture().whenDone((v, cause) -> this.registeredServices.remove(serviceClass)); // Unregister services when the module deactivates. } @Override