forked from StarOpenSource/Engine
Add event precomputation
This commit is contained in:
parent
832ed5cd5c
commit
6be1f7f2cf
4 changed files with 125 additions and 20 deletions
|
@ -19,9 +19,13 @@
|
|||
|
||||
package de.staropensource.sosengine.base;
|
||||
|
||||
import de.staropensource.sosengine.base.classes.Event;
|
||||
import de.staropensource.sosengine.base.classes.SubsystemMainClass;
|
||||
import de.staropensource.sosengine.base.classes.helpers.EventHelper;
|
||||
import de.staropensource.sosengine.base.data.info.EngineInformation;
|
||||
import de.staropensource.sosengine.base.events.EngineCrashEvent;
|
||||
import de.staropensource.sosengine.base.events.EngineShutdownEvent;
|
||||
import de.staropensource.sosengine.base.events.LogEvent;
|
||||
import de.staropensource.sosengine.base.events.internal.InternalEngineShutdownEvent;
|
||||
import de.staropensource.sosengine.base.logging.CrashHandler;
|
||||
import de.staropensource.sosengine.base.logging.LoggerInstance;
|
||||
|
@ -95,6 +99,9 @@ public final class Engine implements SubsystemMainClass {
|
|||
// Populate crash content
|
||||
populateCrashContent();
|
||||
|
||||
// Precompute event listeners
|
||||
precomputeEventListeners();
|
||||
|
||||
// Initialize variables
|
||||
logger = new LoggerInstance(new LogIssuer(getClass(), CodePart.ENGINE));
|
||||
});
|
||||
|
@ -171,6 +178,19 @@ public final class Engine implements SubsystemMainClass {
|
|||
CrashHandler.getCrashContent().put("Stacktrace", "%stacktrace%");
|
||||
}
|
||||
|
||||
/**
|
||||
* Precomputes all base engine events.
|
||||
*
|
||||
* @since 1-alpha0
|
||||
*/
|
||||
public void precomputeEventListeners() {
|
||||
EventHelper.precomputeEventListeners(InternalEngineShutdownEvent.class);
|
||||
|
||||
EventHelper.precomputeEventListeners(EngineCrashEvent.class);
|
||||
EventHelper.precomputeEventListeners(EngineShutdownEvent.class);
|
||||
EventHelper.precomputeEventListeners(LogEvent.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts the engine and JVM down.
|
||||
*
|
||||
|
|
|
@ -186,7 +186,7 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
|||
private boolean loggerForceStandardOutput;
|
||||
|
||||
/**
|
||||
* Makes the {@link Logger} work asynchronous if enabled.
|
||||
* If enabled, will makes the {@link Logger} work asynchronous.
|
||||
*
|
||||
* @since 1-alpha0
|
||||
*
|
||||
|
@ -197,7 +197,21 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
|||
* @see EngineConfiguration#optimizeLogging
|
||||
* @since 1-alpha0
|
||||
*/
|
||||
private boolean optimizeLogging;
|
||||
private boolean optimizeLogging;
|
||||
|
||||
/**
|
||||
* If enabled, allows for {@link java.util.EventListener} precomputation.
|
||||
*
|
||||
* @since 1-alpha0
|
||||
*
|
||||
* -- GETTER --
|
||||
* Gets the value for {@code optimizeEvents}.
|
||||
*
|
||||
* @return variable value
|
||||
* @see EngineConfiguration#optimizeEvents
|
||||
* @since 1-alpha0
|
||||
*/
|
||||
private boolean optimizeEvents;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -248,6 +262,7 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
|||
case "loggerForceStandardOutput" -> loggerForceStandardOutput = parser.getBoolean(group + property);
|
||||
|
||||
case "optimizeLogging" -> optimizeLogging = parser.getBoolean(group + property);
|
||||
case "optimizeEvents" -> optimizeEvents = parser.getBoolean(group + property);
|
||||
}
|
||||
} catch (NullPointerException ignored) {}
|
||||
}
|
||||
|
@ -277,7 +292,8 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
|||
loggerImmediateShutdown = false;
|
||||
loggerForceStandardOutput = false;
|
||||
|
||||
optimizeLogging = false;
|
||||
optimizeLogging = true;
|
||||
optimizeEvents = true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
@ -314,6 +330,9 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
|||
case "optimizeLogging" -> {
|
||||
return optimizeLogging;
|
||||
}
|
||||
case "optimizeEvents" -> {
|
||||
return optimizeEvents;
|
||||
}
|
||||
default -> {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,13 @@ import java.util.*;
|
|||
@Getter
|
||||
@SuppressWarnings({ "unused" })
|
||||
public class EventHelper {
|
||||
/**
|
||||
* Contains all precomputed event listeners.
|
||||
*
|
||||
* @since 1-alpha0
|
||||
*/
|
||||
private static final HashMap<@NotNull Class<? extends Event>, LinkedList<@NotNull Method>> precomputedEventListeners = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
|
@ -64,6 +71,42 @@ public class EventHelper {
|
|||
Logger.diag(new LogIssuer(clazz), "Event " + clazz.getName() + " called with arguments " + ListFormatter.formatArray(arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all annotated methods.
|
||||
*
|
||||
* @param clazz event class
|
||||
* @param forceScanning forces the method to ignore precomputed event listeners
|
||||
* @return list of annotated methods
|
||||
* @since 1-alpha0
|
||||
*/
|
||||
@NotNull
|
||||
public static LinkedList<Method> getAnnotatedMethods(@NotNull Class<? extends Event> clazz, boolean forceScanning) {
|
||||
LinkedList<Method> methods = new LinkedList<>();
|
||||
|
||||
if (forceScanning || !precomputedEventListeners.containsKey(clazz) || EngineConfiguration.getInstance().isOptimizeEvents()) {
|
||||
// Scan entire classpath through Reflections library
|
||||
Reflections reflections = new Reflections(
|
||||
new ConfigurationBuilder()
|
||||
.setUrls(ClasspathHelper.forJavaClassPath())
|
||||
.setScanners(Scanners.MethodsAnnotated)
|
||||
);
|
||||
|
||||
// Get annotated methods
|
||||
Set<@NotNull Method> annotatedMethods = reflections.getMethodsAnnotatedWith(EventListener.class);
|
||||
|
||||
// Sort event listeners not listening for this event out
|
||||
for (Method method : annotatedMethods)
|
||||
if (method.getAnnotation(EventListener.class).event() == clazz)
|
||||
methods.add(method);
|
||||
|
||||
// Sort 'methods' linked list
|
||||
methods.sort(Comparator.comparing(method0 -> method0.getAnnotation(EventListener.class).priority()));
|
||||
} else
|
||||
methods = precomputedEventListeners.get(clazz);
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all annotated methods.
|
||||
*
|
||||
|
@ -73,23 +116,7 @@ public class EventHelper {
|
|||
*/
|
||||
@NotNull
|
||||
public static LinkedList<Method> getAnnotatedMethods(@NotNull Class<? extends Event> clazz) {
|
||||
LinkedList<Method> methods = new LinkedList<>();
|
||||
|
||||
Reflections reflections = new Reflections(
|
||||
new ConfigurationBuilder()
|
||||
.setUrls(ClasspathHelper.forJavaClassPath())
|
||||
.setScanners(Scanners.MethodsAnnotated)
|
||||
);
|
||||
Set<@NotNull Method> annotatedMethods = reflections.getMethodsAnnotatedWith(EventListener.class);
|
||||
|
||||
for (Method method : annotatedMethods)
|
||||
if (method.getAnnotation(EventListener.class).event() == clazz)
|
||||
methods.add(method);
|
||||
|
||||
// Sort 'methods' linked list
|
||||
methods.sort(Comparator.comparing(method0 -> method0.getAnnotation(EventListener.class).priority()));
|
||||
|
||||
return methods;
|
||||
return getAnnotatedMethods(clazz, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,4 +134,40 @@ public class EventHelper {
|
|||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NullPointerException | ExceptionInInitializerError ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Precomputes all event listeners listening on some event.
|
||||
* Will recompute all event listeners if the specified event is already precomputed.
|
||||
*
|
||||
* @param clazz event class to (p)recompute, set to {@code null} to recompute all precomputed events
|
||||
* @since 1-alpha0
|
||||
*/
|
||||
public static void precomputeEventListeners(@Nullable Class<? extends Event> clazz) {
|
||||
if (EngineConfiguration.getInstance().isOptimizeEvents()) return;
|
||||
|
||||
if (clazz == null)
|
||||
for (Class<? extends Event> event : precomputedEventListeners.keySet())
|
||||
precomputeEventListeners(event);
|
||||
else {
|
||||
LinkedList<@NotNull Method> annotatedMethods = getAnnotatedMethods(clazz);
|
||||
|
||||
if (precomputedEventListeners.containsKey(clazz))
|
||||
precomputedEventListeners.replace(clazz, annotatedMethods);
|
||||
else
|
||||
precomputedEventListeners.put(clazz, annotatedMethods);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads precomputed event listeners.
|
||||
*
|
||||
* @param clazz event class to remove precomputed event listeners for, set to {@code null} to remove all precomputed event listeners
|
||||
* @since 1-alpha0
|
||||
*/
|
||||
public static void removePrecomputedEventListeners(@Nullable Class<? extends Event> clazz) {
|
||||
if (clazz == null)
|
||||
precomputedEventListeners.clear();
|
||||
else
|
||||
precomputedEventListeners.remove(clazz);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,9 @@ public final class LogEvent implements Event {
|
|||
* @since 1-alpha0
|
||||
*/
|
||||
public void callEvent(@NotNull LogLevel level, @NotNull LogIssuer logIssuer, @NotNull String message) {
|
||||
// Uncommenting this would be a great way to cause a StackOverflowException!
|
||||
//EventHelper.logCall(getClass(), level, logIssuer, message);
|
||||
|
||||
for (Method method : EventHelper.getAnnotatedMethods(getClass())) {
|
||||
try {
|
||||
method.invoke(null, level, logIssuer, message);
|
||||
|
|
Loading…
Reference in a new issue