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;
|
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.SubsystemMainClass;
|
||||||
|
import de.staropensource.sosengine.base.classes.helpers.EventHelper;
|
||||||
import de.staropensource.sosengine.base.data.info.EngineInformation;
|
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.EngineShutdownEvent;
|
||||||
|
import de.staropensource.sosengine.base.events.LogEvent;
|
||||||
import de.staropensource.sosengine.base.events.internal.InternalEngineShutdownEvent;
|
import de.staropensource.sosengine.base.events.internal.InternalEngineShutdownEvent;
|
||||||
import de.staropensource.sosengine.base.logging.CrashHandler;
|
import de.staropensource.sosengine.base.logging.CrashHandler;
|
||||||
import de.staropensource.sosengine.base.logging.LoggerInstance;
|
import de.staropensource.sosengine.base.logging.LoggerInstance;
|
||||||
|
@ -95,6 +99,9 @@ public final class Engine implements SubsystemMainClass {
|
||||||
// Populate crash content
|
// Populate crash content
|
||||||
populateCrashContent();
|
populateCrashContent();
|
||||||
|
|
||||||
|
// Precompute event listeners
|
||||||
|
precomputeEventListeners();
|
||||||
|
|
||||||
// Initialize variables
|
// Initialize variables
|
||||||
logger = new LoggerInstance(new LogIssuer(getClass(), CodePart.ENGINE));
|
logger = new LoggerInstance(new LogIssuer(getClass(), CodePart.ENGINE));
|
||||||
});
|
});
|
||||||
|
@ -171,6 +178,19 @@ public final class Engine implements SubsystemMainClass {
|
||||||
CrashHandler.getCrashContent().put("Stacktrace", "%stacktrace%");
|
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.
|
* Shuts the engine and JVM down.
|
||||||
*
|
*
|
||||||
|
|
|
@ -186,7 +186,7 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
||||||
private boolean loggerForceStandardOutput;
|
private boolean loggerForceStandardOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the {@link Logger} work asynchronous if enabled.
|
* If enabled, will makes the {@link Logger} work asynchronous.
|
||||||
*
|
*
|
||||||
* @since 1-alpha0
|
* @since 1-alpha0
|
||||||
*
|
*
|
||||||
|
@ -197,7 +197,21 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
||||||
* @see EngineConfiguration#optimizeLogging
|
* @see EngineConfiguration#optimizeLogging
|
||||||
* @since 1-alpha0
|
* @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.
|
* Constructor.
|
||||||
|
@ -248,6 +262,7 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
||||||
case "loggerForceStandardOutput" -> loggerForceStandardOutput = parser.getBoolean(group + property);
|
case "loggerForceStandardOutput" -> loggerForceStandardOutput = parser.getBoolean(group + property);
|
||||||
|
|
||||||
case "optimizeLogging" -> optimizeLogging = parser.getBoolean(group + property);
|
case "optimizeLogging" -> optimizeLogging = parser.getBoolean(group + property);
|
||||||
|
case "optimizeEvents" -> optimizeEvents = parser.getBoolean(group + property);
|
||||||
}
|
}
|
||||||
} catch (NullPointerException ignored) {}
|
} catch (NullPointerException ignored) {}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +292,8 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
||||||
loggerImmediateShutdown = false;
|
loggerImmediateShutdown = false;
|
||||||
loggerForceStandardOutput = false;
|
loggerForceStandardOutput = false;
|
||||||
|
|
||||||
optimizeLogging = false;
|
optimizeLogging = true;
|
||||||
|
optimizeEvents = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
|
@ -314,6 +330,9 @@ public final class EngineConfiguration implements SubsystemConfiguration {
|
||||||
case "optimizeLogging" -> {
|
case "optimizeLogging" -> {
|
||||||
return optimizeLogging;
|
return optimizeLogging;
|
||||||
}
|
}
|
||||||
|
case "optimizeEvents" -> {
|
||||||
|
return optimizeEvents;
|
||||||
|
}
|
||||||
default -> {
|
default -> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,13 @@ import java.util.*;
|
||||||
@Getter
|
@Getter
|
||||||
@SuppressWarnings({ "unused" })
|
@SuppressWarnings({ "unused" })
|
||||||
public class EventHelper {
|
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.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
|
@ -64,6 +71,42 @@ public class EventHelper {
|
||||||
Logger.diag(new LogIssuer(clazz), "Event " + clazz.getName() + " called with arguments " + ListFormatter.formatArray(arguments));
|
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.
|
* Returns all annotated methods.
|
||||||
*
|
*
|
||||||
|
@ -73,23 +116,7 @@ public class EventHelper {
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static LinkedList<Method> getAnnotatedMethods(@NotNull Class<? extends Event> clazz) {
|
public static LinkedList<Method> getAnnotatedMethods(@NotNull Class<? extends Event> clazz) {
|
||||||
LinkedList<Method> methods = new LinkedList<>();
|
return getAnnotatedMethods(clazz, false);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,4 +134,40 @@ public class EventHelper {
|
||||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NullPointerException | ExceptionInInitializerError ignored) {}
|
} 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
|
* @since 1-alpha0
|
||||||
*/
|
*/
|
||||||
public void callEvent(@NotNull LogLevel level, @NotNull LogIssuer logIssuer, @NotNull String message) {
|
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())) {
|
for (Method method : EventHelper.getAnnotatedMethods(getClass())) {
|
||||||
try {
|
try {
|
||||||
method.invoke(null, level, logIssuer, message);
|
method.invoke(null, level, logIssuer, message);
|
||||||
|
|
Loading…
Reference in a new issue