From b74292c336e4a2b75d26d0f7aa945785f88ce1cc Mon Sep 17 00:00:00 2001 From: Daniil Date: Thu, 26 Jul 2018 11:08:56 +0700 Subject: [PATCH] Splitting AdvancedEventLoop and AsyncEventLoop for the sake of comparision --- .../core/events/async/AdvancedEventLoop.java | 145 ++++++++++++++++++ .../mc/core/events/async/AsyncEventLoop.java | 111 +------------- 2 files changed, 149 insertions(+), 107 deletions(-) create mode 100644 event-loop/src/main/java/mc/core/events/async/AdvancedEventLoop.java diff --git a/event-loop/src/main/java/mc/core/events/async/AdvancedEventLoop.java b/event-loop/src/main/java/mc/core/events/async/AdvancedEventLoop.java new file mode 100644 index 0000000..9b8a4e2 --- /dev/null +++ b/event-loop/src/main/java/mc/core/events/async/AdvancedEventLoop.java @@ -0,0 +1,145 @@ +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 AdvancedEventLoop extends BaseEventLoop { + Map, List> handlers = new HashMap<>(); + + @Override + public void callEvent(Event event) { + Class eventType = event.getClass(); + if (handlers.containsKey(eventType)) { + for (ExecutorLink link : handlers.get(eventType)) { + if (link.isIgnoreCancelled() && event.isCanceled()) + continue; + + Object preprocessResult = null; + if (link.getPreprocessMethod() != null) { + try { + preprocessResult = 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 { + if (link.getResultInjection() != null) + link.getMethod().invoke(link.object, event, preprocessResult); + else + 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 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.methodName())) + log.warn("Attempted to register multiple EventPreprocessors for the event {}. Please note, that only the last one will be registered.", annotation.methodName()); + preprocessors.put(annotation.methodName() + ":" + firstParamType.getSimpleName(), method); + } + + + for (Method method : object.getClass().getDeclaredMethods()) { + EventHandler annotation = method.getAnnotation(EventHandler.class); + + if (annotation == null) + continue; + + if (!Modifier.isPublic(method.getModifiers())) { + log.error("Unable to register {} as an EventHandler. Method must have a 'private' access modifier.", method.toString()); + continue; + + } + + if (method.getParameterCount() == 0) { + log.error("Unable to register {} as an EventHandler. Method must at least one argument.", method.toString()); + continue; + } + + Class firstParamType = method.getParameterTypes()[0]; + if (!Event.class.isAssignableFrom(firstParamType)) { + log.error("Unable to register {} as an EventHandler. First parameter type must implement 'Event' interface.", method.toString()); + continue; + } + @SuppressWarnings("unchecked") Class eventType = (Class) method.getParameterTypes()[0]; + + Method preprocessMethod = preprocessors.get(method.getName() + ":" + eventType.getSimpleName()); + Class resultInjection = null; + if (preprocessMethod.getReturnType() != void.class && method.getParameterCount() == 2 && preprocessMethod.getReturnType().equals(method.getParameterTypes()[1])) + resultInjection = preprocessMethod.getReturnType(); + + if (resultInjection == null && method.getParameterCount() > 1) { + log.error("Unable to register {} as an EventHandler. Method has {} arguments, but no EventPreprocessors found to provide DI for type {}", method.toString(), method.getParameterCount(), method.getParameterTypes()[1].toString()); + continue; + } + + if (resultInjection == null && preprocessMethod.getReturnType() != void.class) { + log.warn("DI registration for EventHandler {} failed. Injection target not found", method.toString()); + } + + List eventHandlers = handlers.computeIfAbsent(eventType, s -> new ArrayList<>()); + eventHandlers.add(new ExecutorLink(annotation.priority().getValue(), annotation.ignoreCancelled(), method, object, preprocessMethod, resultInjection)); + eventHandlers.sort(Comparator.comparingInt(o -> o.priority)); + + preprocessors.remove(method.getName() + ":" + eventType.getSimpleName()); + } + + for (Map.Entry preprocessor : preprocessors.entrySet()) + log.error("EventPreprocessor ({}) missing target: unable to find target method ({})", preprocessor.getValue(), preprocessor.getKey()); + + } + + /** + * This class describes + */ + @RequiredArgsConstructor + @Getter + static class ExecutorLink { + private final int priority; + private final boolean ignoreCancelled; + private final Method method; + private final Object object; + private final Method preprocessMethod; + private final Class resultInjection; + } +} + diff --git a/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java b/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java index 8ee1ab6..61a12f9 100644 --- a/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java +++ b/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java @@ -1,24 +1,17 @@ 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.*; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @SuppressWarnings("Duplicates") @Slf4j -public class AsyncEventLoop extends BaseEventLoop { - private Map, List> handlers = new HashMap<>(); +public class AsyncEventLoop extends AdvancedEventLoop { private ExecutorService preEventExecutor = Executors.newSingleThreadExecutor(); @Override @@ -51,110 +44,14 @@ public class AsyncEventLoop extends BaseEventLoop { try { if (link.getResultInjection() != null) - link.getMethod().invoke(link.object, event, eventBatch.getInjectionObject(i)); + link.getMethod().invoke(link.getObject(), event, eventBatch.getInjectionObject(i)); else - link.getMethod().invoke(link.object, event); + link.getMethod().invoke(link.getObject(), event); } catch (IllegalAccessException | InvocationTargetException e) { log.error("Exception caught while attempting to dispatch {}.", eventType.getSimpleName(), e); } } } } - - @Override - public void addEventHandler(Object object) { - Map 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.methodName())) - log.warn("Attempted to register multiple EventPreprocessors for the event {}. Please note, that only the last one will be registered.", annotation.methodName()); - preprocessors.put(annotation.methodName() + ":" + firstParamType.getSimpleName(), method); - } - - - for (Method method : object.getClass().getDeclaredMethods()) { - EventHandler annotation = method.getAnnotation(EventHandler.class); - - if (annotation == null) - continue; - - if (!Modifier.isPublic(method.getModifiers())) { - log.error("Unable to register {} as an EventHandler. Method must have a 'private' access modifier.", method.toString()); - continue; - - } - - if (method.getParameterCount() == 0) { - log.error("Unable to register {} as an EventHandler. Method must at least one argument.", method.toString()); - continue; - } - - Class firstParamType = method.getParameterTypes()[0]; - if (!Event.class.isAssignableFrom(firstParamType)) { - log.error("Unable to register {} as an EventHandler. First parameter type must implement 'Event' interface.", method.toString()); - continue; - } - @SuppressWarnings("unchecked") Class eventType = (Class) method.getParameterTypes()[0]; - - Method preprocessMethod = preprocessors.get(method.getName() + ":" + eventType.getSimpleName()); - Class resultInjection = null; - if (preprocessMethod.getReturnType() != void.class && method.getParameterCount() == 2 && preprocessMethod.getReturnType().equals(method.getParameterTypes()[1])) - resultInjection = preprocessMethod.getReturnType(); - - if (resultInjection == null && method.getParameterCount() > 1) { - log.error("Unable to register {} as an EventHandler. Method has {} arguments, but no EventPreprocessors found to provide DI for type {}", method.toString(), method.getParameterCount(), method.getParameterTypes()[1].toString()); - continue; - } - - if (resultInjection == null && preprocessMethod.getReturnType() != void.class) { - log.warn("DI registration for EventHandler {} failed. Injection target not found", method.toString()); - } - - List eventHandlers = handlers.computeIfAbsent(eventType, s -> new ArrayList<>()); - eventHandlers.add(new ExecutorLink(annotation.priority().getValue(), annotation.ignoreCancelled(), method, object, preprocessMethod, resultInjection)); - eventHandlers.sort(Comparator.comparingInt(o -> o.priority)); - - preprocessors.remove(method.getName() + ":" + eventType.getSimpleName()); - } - - for (Map.Entry preprocessor : preprocessors.entrySet()) - log.error("EventPreprocessor ({}) missing target: unable to find target method ({})", preprocessor.getValue(), preprocessor.getKey()); - - } - - /** - * This class describes - */ - @RequiredArgsConstructor - @Getter - static class ExecutorLink { - private final int priority; - private final boolean ignoreCancelled; - private final Method method; - private final Object object; - private final Method preprocessMethod; - private final Class resultInjection; - } }