Improve and fix events

This commit is contained in:
JeremyStar™ 2024-06-09 22:14:45 +02:00
parent 5a98722520
commit 3256224329
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
9 changed files with 150 additions and 141 deletions

View file

@ -91,9 +91,6 @@ public final class Engine {
// Initialize classes // Initialize classes
initializeClasses(); initializeClasses();
// Initialize events
initializeEvents();
// Populate crash content // Populate crash content
populateCrashContent(); populateCrashContent();
@ -119,14 +116,6 @@ public final class Engine {
new ShortcodeConverter(); new ShortcodeConverter();
} }
/**
* Initializes all events.
*
* @since 1-alpha0
*/
private void initializeEvents() {
}
/** /**
* This method populates the Crash Handler's content with the default set of content. * This method populates the Crash Handler's content with the default set of content.
* *

View file

@ -20,15 +20,29 @@
package de.staropensource.sosengine.base.annotations; package de.staropensource.sosengine.base.annotations;
import de.staropensource.sosengine.base.classes.Event; import de.staropensource.sosengine.base.classes.Event;
import de.staropensource.sosengine.base.classes.EventPriority;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* Annotation for registering events on methods. * Annotation for registering events on methods.
*/ */
@SuppressWarnings("unused")
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Documented @Documented
public @interface EventListener { public @interface EventListener {
/**
* The event to listen for.
*
* @return the event the method listens for
*/
Class<? extends Event> event(); Class<? extends Event> event();
/**
* The priority of the event.
*
* @return the event priority
*/
EventPriority priority();
} }

View file

@ -1,131 +1,14 @@
/*
STAROPENSOURCE ENGINE SOURCE FILE
Copyright (c) 2024 The StarOpenSource Engine Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.sosengine.base.classes; package de.staropensource.sosengine.base.classes;
import de.staropensource.sosengine.base.annotations.EventListener;
import de.staropensource.sosengine.base.logging.Logger;
import de.staropensource.sosengine.base.types.CodePart;
import de.staropensource.sosengine.base.types.LogIssuer;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/** /**
* Represents an event. * Represents an event.
* *
* @since 1-alpha0 * @since 1-alpha0
*/ */
@Getter @SuppressWarnings({ "unused" })
@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) public interface Event {
public abstract class Event {
/** /**
* Instance. * Calls the event.
*
* @since 1-alpha0
*
* -- GETTER --
* Returns the extending {@link Event} instance.
*
* @return extending {@link Event} instance
* @since 1-alpha0
*/ */
@Getter() void callEvent();
protected static Event instance;
/**
* The name of the event.
*
* @since 1-alpha0
*
* -- GETTER --
* Returns the name of the event.
*
* @return the event name
* @since 1-alpha0
*/
@NotNull
private final String eventName;
/**
* Constructor.
*
* @since 1-alpha0
*/
public Event() {
this.eventName = this.getClass().getName().replace(this.getClass().getPackage() + ".", "");
// Only allow one instance
if (instance == null)
instance = this;
else
Logger.crash(new LogIssuer(getClass(), CodePart.ENGINE), "Tried reinitializing " + getClass().getName() + " twice");
}
/**
* Returns all annotated methods.
*
* @return list of annotated methods
* @since 1-alpha0
*/
@NotNull
protected List<Method> getAnnotatedMethods() {
List<Method> methods = new ArrayList<>();
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forJavaClassPath())
.setScanners(Scanners.MethodsAnnotated)
);
Set<Method> annotatedMethods = reflections.getMethodsAnnotatedWith(EventListener.class);
for (Method method : annotatedMethods)
if (method.getAnnotation(EventListener.class).event() == this.getClass())
methods.add(method);
return methods;
}
/**
* Invokes all annotated methods without any arguments.
*/
protected void invokeAnnotatedMethods() {
for (Method method : getAnnotatedMethods()) {
try {
method.invoke(null);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NullPointerException | ExceptionInInitializerError ignored) {}
}
}
/**
* Calls the event and notifies all annotated methods about it.
*
* @since 1-alpha0
*/
public abstract void callEvent();
} }

View file

@ -0,0 +1,39 @@
package de.staropensource.sosengine.base.classes;
/**
* Determines in which order events are processed.
*/
@SuppressWarnings("unused")
public enum EventPriority {
/**
* Events with this priority are processed first.
* This event is exclusive to subsystems and should not be used by applications.
*/
EXTREMELY_IMPORTANT,
/**
* Events with this priority are processed after {@code EXTREMELY_IMPORTANT}.
*/
VERY_IMPORTANT,
/**
* Events with this priority are processed after {@code VERY_IMPORTANT}.
*/
IMPORTANT,
/**
* Events with this priority are processed after {@code IMPORTANT}.
*/
UNIMPORTANT,
/**
* Events with this priority are processed after {@code UNIMPORTANT}.
*/
VERY_UNIMPORTANT,
/**
* Events with this priority are processed last.
* This event is exclusive to subsystems and should not be used by applications.
*/
EXTREMELY_UNIMPORTANT,
}

View file

@ -20,6 +20,7 @@
package de.staropensource.sosengine.base.events; package de.staropensource.sosengine.base.events;
import de.staropensource.sosengine.base.classes.Event; import de.staropensource.sosengine.base.classes.Event;
import de.staropensource.sosengine.base.utility.EventHelper;
/** /**
* Called in the event of an engine crash, just before the JVM exists. * Called in the event of an engine crash, just before the JVM exists.
@ -27,10 +28,10 @@ import de.staropensource.sosengine.base.classes.Event;
* @since 1-alpha0 * @since 1-alpha0
*/ */
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
public final class EngineCrashEvent extends Event { public final class EngineCrashEvent implements Event {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void callEvent() { public void callEvent() {
invokeAnnotatedMethods(); EventHelper.invokeAnnotatedMethods(getClass());
} }
} }

View file

@ -22,6 +22,7 @@ package de.staropensource.sosengine.base.events;
import de.staropensource.sosengine.base.classes.Event; import de.staropensource.sosengine.base.classes.Event;
import de.staropensource.sosengine.base.types.LogIssuer; import de.staropensource.sosengine.base.types.LogIssuer;
import de.staropensource.sosengine.base.types.LogLevel; import de.staropensource.sosengine.base.types.LogLevel;
import de.staropensource.sosengine.base.utility.EventHelper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -33,16 +34,16 @@ import java.lang.reflect.Method;
* @since 1-alpha0 * @since 1-alpha0
*/ */
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
public final class LogEvent extends Event { public final class LogEvent implements Event {
/** /**
* {@inheritDoc} * {@inheritDoc}
* @deprecated use the {@code callEvent} method with arguments * @deprecated use the {@code callEvent} method with arguments
* @see LogEvent#callEventNew(LogLevel, LogIssuer, String) * @see LogEvent#callEvent(LogLevel, LogIssuer, String)
*/ */
@Deprecated @Deprecated
@Override @Override
public void callEvent() { public void callEvent() {
invokeAnnotatedMethods(); EventHelper.invokeAnnotatedMethods(getClass());
} }
/** /**
@ -50,8 +51,8 @@ public final class LogEvent extends Event {
* *
* @since 1-alpha0 * @since 1-alpha0
*/ */
public void callEventNew(@NotNull LogLevel level, @NotNull LogIssuer logIssuer, @NotNull String message) { public void callEvent(@NotNull LogLevel level, @NotNull LogIssuer logIssuer, @NotNull String message) {
for (Method method : getAnnotatedMethods()) { for (Method method : EventHelper.getAnnotatedMethods(getClass())) {
try { try {
method.invoke(null, level, logIssuer, message); method.invoke(null, level, logIssuer, message);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NullPointerException | ExceptionInInitializerError ignored) {} } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NullPointerException | ExceptionInInitializerError ignored) {}

View file

@ -144,7 +144,7 @@ public final class CrashHandler {
Logger.getLoggerImplementation().print(LogLevel.CRASH, logIssuer, base); Logger.getLoggerImplementation().print(LogLevel.CRASH, logIssuer, base);
// Send EngineCrash event // Send EngineCrash event
EngineCrashEvent.getInstance().callEvent(); new EngineCrashEvent().callEvent();
// Shutdown JVM // Shutdown JVM
if (EngineConfiguration.getInstance().isLoggerImmediateShutdown()) if (EngineConfiguration.getInstance().isLoggerImmediateShutdown())

View file

@ -115,7 +115,7 @@ public final class Logger {
base = loggerImplementation.postPlaceholder(level, logIssuer, base); base = loggerImplementation.postPlaceholder(level, logIssuer, base);
// Call event // Call event
((LogEvent) LogEvent.getInstance()).callEventNew(level, logIssuer, message); new LogEvent().callEvent(level, logIssuer, message);
// Print log message // Print log message
loggerImplementation.print(level, logIssuer, base); loggerImplementation.print(level, logIssuer, base);

View file

@ -0,0 +1,82 @@
/*
STAROPENSOURCE ENGINE SOURCE FILE
Copyright (c) 2024 The StarOpenSource Engine Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.sosengine.base.utility;
import de.staropensource.sosengine.base.annotations.EventListener;
import de.staropensource.sosengine.base.classes.Event;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
/**
* Represents an event.
*
* @since 1-alpha0
*/
@Getter
@SuppressWarnings({ "unused" })
public class EventHelper {
/**
* Returns all annotated methods.
*
* @return list of annotated methods
* @since 1-alpha0
*/
@NotNull
public static LinkedList<Method> getAnnotatedMethods(Class<? extends Event> clazz) {
LinkedList<Method> methods = new LinkedList<>();
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forJavaClassPath())
.setScanners(Scanners.MethodsAnnotated)
);
Set<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;
}
/**
* Invokes all annotated methods without any arguments.
*
* @since 1-alpha0
*/
public static void invokeAnnotatedMethods(Class<? extends Event> clazz) {
for (Method method : getAnnotatedMethods(clazz)) {
try {
method.invoke(null);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NullPointerException | ExceptionInInitializerError ignored) {}
}
}
}