Preprocessing concept implementation
This commit is contained in:
@@ -7,35 +7,28 @@ import java.lang.reflect.Modifier;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class BaseEventLoop implements EventLoop {
|
public abstract class BaseEventLoop implements EventLoop {
|
||||||
@Override
|
|
||||||
public void addEventHandler(Object object) {
|
protected boolean notValidEventHandler(EventHandler annotation, Method method) {
|
||||||
for (Method method : object.getClass().getDeclaredMethods()) {
|
|
||||||
EventHandler annotation = method.getAnnotation(EventHandler.class);
|
|
||||||
if (annotation == null)
|
if (annotation == null)
|
||||||
continue; // We are not interested in methods without @EventHandler annotation
|
return true;
|
||||||
|
|
||||||
if (!Modifier.isPublic(method.getModifiers())) {
|
if (!Modifier.isPublic(method.getModifiers())) {
|
||||||
log.error("Unable to register {} as an EventHandler. Method must have a 'private' access modifier.", method.toString());
|
log.error("Unable to register {} as an EventHandler. Method must have a 'private' access modifier.", method.toString());
|
||||||
continue;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method.getParameterCount() != 1) {
|
if (method.getParameterCount() != 1) {
|
||||||
log.error("Unable to register {} as an EventHandler. Method must have exactly one argument.", method.toString());
|
log.error("Unable to register {} as an EventHandler. Method must have exactly one argument.", method.toString());
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> firstParamType = method.getParameterTypes()[0];
|
Class<?> firstParamType = method.getParameterTypes()[0];
|
||||||
if (!Event.class.isAssignableFrom(firstParamType)) {
|
if (!Event.class.isAssignableFrom(firstParamType)) {
|
||||||
log.error("Unable to register {} as an EventHandler. First parameter type must implement 'Event' interface.", method.toString());
|
log.error("Unable to register {} as an EventHandler. First parameter type must implement 'Event' interface.", method.toString());
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") Class<? extends Event> eventType = (Class<? extends Event>) firstParamType;
|
return false;
|
||||||
|
|
||||||
registerMethod(object, method, annotation, eventType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void registerMethod(Object object, Method method, EventHandler annotation, Class<? extends Event> eventType);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -27,11 +26,21 @@ public class SimpleEventLoop extends BaseEventLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void registerMethod(Object object, Method method, EventHandler annotation, Class<? extends Event> eventType) {
|
@Override
|
||||||
|
public void addEventHandler(Object object) {
|
||||||
|
for (Method method : object.getClass().getDeclaredMethods()) {
|
||||||
|
EventHandler annotation = method.getAnnotation(EventHandler.class);
|
||||||
|
|
||||||
|
if (notValidEventHandler(annotation, method))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") Class<? extends Event> eventType = (Class<? extends Event>) method.getParameterTypes()[0];
|
||||||
|
|
||||||
List<SimpleEventLoop.ExecutorLink> eventHandlers = handlers.computeIfAbsent(eventType, s -> new ArrayList<>());
|
List<SimpleEventLoop.ExecutorLink> eventHandlers = handlers.computeIfAbsent(eventType, s -> new ArrayList<>());
|
||||||
eventHandlers.add(new SimpleEventLoop.ExecutorLink(annotation.priority().getValue(), annotation.ignoreCancelled(), method, object));
|
eventHandlers.add(new SimpleEventLoop.ExecutorLink(annotation.priority().getValue(), annotation.ignoreCancelled(), method, object));
|
||||||
eventHandlers.sort(Comparator.comparingInt(o -> o.priority));
|
eventHandlers.sort(Comparator.comparingInt(o -> o.priority));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class describes
|
* This class describes
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package mc.core.events.async;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import mc.core.events.BaseEventLoop;
|
||||||
|
import mc.core.events.Event;
|
||||||
|
import mc.core.events.EventHandler;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
|
@Slf4j
|
||||||
|
public class AsyncEventLoop extends BaseEventLoop {
|
||||||
|
private Map<Class<? extends Event>, List<ExecutorLink>> handlers = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void callEvent(Event event) {
|
||||||
|
Class<? extends Event> eventType = event.getClass();
|
||||||
|
if (handlers.containsKey(eventType)) {
|
||||||
|
for (ExecutorLink link : handlers.get(eventType)) {
|
||||||
|
if (link.getPreprocessMethod() != null) {
|
||||||
|
try {
|
||||||
|
link.getPreprocessMethod().invoke(link.object, event);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
log.error("Exception caught while attempting to run event preprocessing for {}.", eventType.getSimpleName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
link.getMethod().invoke(link.object, event);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
log.error("Exception caught while attempting to dispatch {}.", eventType.getSimpleName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addEventHandler(Object object) {
|
||||||
|
Map<String, Method> preprocessors = new HashMap<>();
|
||||||
|
|
||||||
|
for (Method method : object.getClass().getDeclaredMethods()) {
|
||||||
|
EventPreprocessor annotation = method.getAnnotation(EventPreprocessor.class);
|
||||||
|
if (annotation == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!Modifier.isPublic(method.getModifiers())) {
|
||||||
|
log.error("Unable to register {} as an EventPreprocessor. Method must have a 'private' access modifier.", method.toString());
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.getParameterCount() != 1) {
|
||||||
|
log.error("Unable to register {} as an EventPreprocessor. Method must have exactly one argument.", method.toString());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?> firstParamType = method.getParameterTypes()[0];
|
||||||
|
if (!Event.class.isAssignableFrom(firstParamType)) {
|
||||||
|
log.error("Unable to register {} as an EventPreprocessor. First parameter type must implement 'Event' interface.", method.toString());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preprocessors.containsKey(annotation.eventName()))
|
||||||
|
log.warn("Attempted to register multiple EventPreprocessors for the event {}. Please note, that only the last one will be registered.", annotation.eventName());
|
||||||
|
preprocessors.put(annotation.eventName(), method);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (Method method : object.getClass().getDeclaredMethods()) {
|
||||||
|
EventHandler annotation = method.getAnnotation(EventHandler.class);
|
||||||
|
|
||||||
|
if (notValidEventHandler(annotation, method))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") Class<? extends Event> eventType = (Class<? extends Event>) method.getParameterTypes()[0];
|
||||||
|
|
||||||
|
List<ExecutorLink> eventHandlers = handlers.computeIfAbsent(eventType, s -> new ArrayList<>());
|
||||||
|
eventHandlers.add(new ExecutorLink(annotation.priority().getValue(), annotation.ignoreCancelled(), method, object, preprocessors.remove(method.getName())));
|
||||||
|
eventHandlers.sort(Comparator.comparingInt(o -> o.priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, Method> preprocessor : preprocessors.entrySet())
|
||||||
|
log.error("EventPreprocessor ({}) missing target: unable to find target method ({})", preprocessor.getValue(), preprocessor.getKey());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class describes
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
private static class ExecutorLink {
|
||||||
|
private final int priority;
|
||||||
|
private final boolean ignoreCancelled;
|
||||||
|
private final Method method;
|
||||||
|
private final Object object;
|
||||||
|
private final Method preprocessMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package mc.core.events.async;
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Inherited
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface EventPreprocessor {
|
||||||
|
String eventName();
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package ru.core.events;
|
||||||
|
|
||||||
|
import mc.core.events.LoginEvent;
|
||||||
|
import mc.core.events.async.AsyncEventLoop;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import ru.core.events.handlers.AsyncEventHandler;
|
||||||
|
|
||||||
|
public class AsyncEventLoopTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loopWorks() {
|
||||||
|
AsyncEventLoop asyncEventLoop = new AsyncEventLoop();
|
||||||
|
asyncEventLoop.addEventHandler(new AsyncEventHandler());
|
||||||
|
LoginEvent testEvent = new LoginEvent(null);
|
||||||
|
testEvent.setDenyReason("none");
|
||||||
|
|
||||||
|
asyncEventLoop.callEvent(testEvent);
|
||||||
|
|
||||||
|
Assert.assertEquals("Event handler was not called", "Hello from Async Event Handler!", testEvent.getDenyReason());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package ru.core.events.handlers;
|
||||||
|
|
||||||
|
import mc.core.events.EventHandler;
|
||||||
|
import mc.core.events.LoginEvent;
|
||||||
|
import mc.core.events.async.EventPreprocessor;
|
||||||
|
|
||||||
|
public class AsyncEventHandler {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onLogin(LoginEvent event) {
|
||||||
|
event.setDenyReason("Hello from Async Event Handler!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventPreprocessor(eventName = "onLogin")
|
||||||
|
public void onLoginPreprocess(LoginEvent event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user