Skip to content

Commit

Permalink
Made ModuleEnvironment able to support additions
Browse files Browse the repository at this point in the history
  • Loading branch information
BomBardyGamer committed Aug 3, 2023
1 parent d75933d commit e69aa43
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 34 deletions.
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}

withSourcesJar()
withJavadocJar()
}

publishing {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/dev/emortal/api/modules/LoadableModule.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package dev.emortal.api.modules;

import java.io.IOException;
import dev.emortal.api.modules.env.ModuleEnvironment;
import org.jetbrains.annotations.NotNull;

public record LoadableModule(@NotNull Class<? extends Module> clazz, @NotNull Creator creator) {

@FunctionalInterface
public interface Creator {

@NotNull Module create(@NotNull ModuleEnvironment environment) throws IOException;
@NotNull Module create(@NotNull ModuleEnvironment environment) throws Exception;
}
}
3 changes: 2 additions & 1 deletion src/main/java/dev/emortal/api/modules/Module.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.emortal.api.modules;

import dev.emortal.api.modules.env.ModuleEnvironment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -12,7 +13,7 @@ protected Module(@NotNull ModuleEnvironment environment) {
}

protected <T extends Module> @Nullable T getModule(@NotNull Class<T> type) {
return environment.moduleProvider().getModule(type);
return this.environment.moduleProvider().getModule(type);
}

public abstract boolean onLoad();
Expand Down
6 changes: 0 additions & 6 deletions src/main/java/dev/emortal/api/modules/ModuleEnvironment.java

This file was deleted.

64 changes: 39 additions & 25 deletions src/main/java/dev/emortal/api/modules/ModuleManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import dev.emortal.api.modules.env.BasicModuleEnvironment;
import dev.emortal.api.modules.env.ModuleEnvironment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jgrapht.Graph;
Expand All @@ -20,41 +23,52 @@
public final class ModuleManager implements ModuleProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(ModuleManager.class);

private final @NotNull ModuleEnvironment.Provider moduleEnvironmentProvider;

private final Map<Class<? extends Module>, Module> modules = new ConcurrentHashMap<>();

public ModuleManager(@NotNull List<LoadableModule> modules, @NotNull ModuleEnvironment.Provider moduleEnvironmentProvider) {
this.moduleEnvironmentProvider = moduleEnvironmentProvider;
this.loadModules(modules);
}

public ModuleManager(@NotNull List<LoadableModule> modules) {
this(modules, BasicModuleEnvironment::new);
}

private void loadModules(@NotNull List<LoadableModule> modules) {
if (modules.isEmpty()) {
LOGGER.warn("No modules provided to ModuleManager to be loaded");
return;
}

final List<LoadableModule> sortedModules = sortModules(modules);
List<LoadableModule> sortedModules = this.sortModules(modules);

for (final LoadableModule loadable : sortedModules) {
final ModuleData data = loadable.clazz().getDeclaredAnnotation(ModuleData.class);
for (LoadableModule loadable : sortedModules) {
ModuleData data = loadable.clazz().getDeclaredAnnotation(ModuleData.class);
if (data == null) {
LOGGER.error("Module class {} does not have a ModuleData annotation! Skipping...", loadable.clazz().getSimpleName());
continue;
}

final ModuleEnvironment environment = new ModuleEnvironment(data, this);
final Module module;
ModuleEnvironment environment = this.moduleEnvironmentProvider.create(data, this);
Module module;
try {
module = loadable.creator().create(environment);
} catch (final Exception exception) {
} catch (Exception exception) {
LOGGER.error("Failed to create module {}", data.name(), exception);
continue;
}

final Instant loadStart = Instant.now();
final boolean loadResult;
Instant loadStart = Instant.now();
boolean loadResult;
try {
loadResult = module.onLoad();
} catch (final Exception exception) {
} catch (Exception exception) {
LOGGER.error("Failed to load module {}", data.name(), exception);
continue;
}
final Duration loadDuration = Duration.between(loadStart, Instant.now());
Duration loadDuration = Duration.between(loadStart, Instant.now());

if (loadResult) {
this.modules.put(loadable.clazz(), module);
Expand All @@ -65,39 +79,39 @@ public ModuleManager(@NotNull List<LoadableModule> modules) {

@Override
public <T extends Module> @Nullable T getModule(@NotNull Class<T> type) {
return type.cast(modules.get(type));
return type.cast(this.modules.get(type));
}

public void onReady() {
for (final Module module : modules.values()) {
final Instant readyStart = Instant.now();
for (Module module : this.modules.values()) {
Instant readyStart = Instant.now();
module.onReady();
final Duration readyDuration = Duration.between(readyStart, Instant.now());
Duration readyDuration = Duration.between(readyStart, Instant.now());

LOGGER.info("Fired onReady for module {} in {}ms", module.getClass().getSimpleName(), readyDuration.toMillis());
}
}

public void onUnload() {
for (final Module module : modules.values()) {
final Instant unloadStart = Instant.now();
for (Module module : this.modules.values()) {
Instant unloadStart = Instant.now();
module.onUnload();
final Duration unloadDuration = Duration.between(unloadStart, Instant.now());
Duration unloadDuration = Duration.between(unloadStart, Instant.now());

LOGGER.info("Unloaded module {} in {}ms", module.getClass().getSimpleName(), unloadDuration.toMillis());
}
}

private List<LoadableModule> sortModules(Collection<LoadableModule> modules) throws IllegalArgumentException {
final Graph<LoadableModule, DefaultEdge> graph = new DirectedAcyclicGraph<>(DefaultEdge.class);
private @NotNull List<LoadableModule> sortModules(@NotNull Collection<LoadableModule> modules) {
Graph<LoadableModule, DefaultEdge> graph = new DirectedAcyclicGraph<>(DefaultEdge.class);

for (final LoadableModule module : modules) {
for (LoadableModule module : modules) {
graph.addVertex(module);

final ModuleData data = module.clazz().getDeclaredAnnotation(ModuleData.class);
for (final Class<? extends Module> dependency : data.softDependencies()) {
ModuleData data = module.clazz().getDeclaredAnnotation(ModuleData.class);
for (Class<? extends Module> dependency : data.softDependencies()) {
// find the LoadableModule for the dependency's Class
final LoadableModule dependencyModule = modules.stream()
LoadableModule dependencyModule = modules.stream()
.filter(targetModule -> targetModule.clazz().equals(dependency))
.findFirst()
.orElse(null);
Expand All @@ -111,8 +125,8 @@ private List<LoadableModule> sortModules(Collection<LoadableModule> modules) thr
}
}

final TopologicalOrderIterator<LoadableModule, DefaultEdge> sortedIterator = new TopologicalOrderIterator<>(graph);
final List<LoadableModule> sorted = new ArrayList<>();
TopologicalOrderIterator<LoadableModule, DefaultEdge> sortedIterator = new TopologicalOrderIterator<>(graph);
List<LoadableModule> sorted = new ArrayList<>();
sortedIterator.forEachRemaining(sorted::add);

LOGGER.info("Loading modules: [{}]", sorted.stream().map(module -> module.clazz().getSimpleName()).collect(Collectors.joining(", ")));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.emortal.api.modules.env;

import dev.emortal.api.modules.ModuleData;
import dev.emortal.api.modules.ModuleProvider;
import org.jetbrains.annotations.NotNull;

/**
* The basic environment that only includes the required fields.
*/
public record BasicModuleEnvironment(@NotNull ModuleData data, @NotNull ModuleProvider moduleProvider) implements ModuleEnvironment {
}
27 changes: 27 additions & 0 deletions src/main/java/dev/emortal/api/modules/env/ModuleEnvironment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.emortal.api.modules.env;

import dev.emortal.api.modules.ModuleData;
import dev.emortal.api.modules.ModuleProvider;
import org.jetbrains.annotations.NotNull;

/**
* The environment that a module is loaded in.
*/
public interface ModuleEnvironment {

/**
* Data provided by the module.
*/
@NotNull ModuleData data();

/**
* Provides access to existing modules to facilitate module dependencies.
*/
@NotNull ModuleProvider moduleProvider();

@FunctionalInterface
interface Provider {

@NotNull ModuleEnvironment create(@NotNull ModuleData data, @NotNull ModuleProvider moduleProvider);
}
}

0 comments on commit e69aa43

Please sign in to comment.