From 8fef2840192f72590670aaf7ef85dfe20c1490d8 Mon Sep 17 00:00:00 2001 From: Daniil Date: Wed, 25 Jul 2018 22:58:30 +0700 Subject: [PATCH] Implementation of Return Injection --- .../mc/core/events/async/AsyncEventLoop.java | 51 ++++++++++++++++--- .../core/events/async/EventPreprocessor.java | 2 +- .../ru/core/events/AsyncEventLoopTest.java | 2 +- .../events/handlers/AsyncEventHandler.java | 18 ++++--- 4 files changed, 58 insertions(+), 15 deletions(-) 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 283d9dc..66936e5 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 @@ -22,16 +22,20 @@ public class AsyncEventLoop extends BaseEventLoop { Class eventType = event.getClass(); if (handlers.containsKey(eventType)) { for (ExecutorLink link : handlers.get(eventType)) { + Object preprocessResult = null; if (link.getPreprocessMethod() != null) { try { - link.getPreprocessMethod().invoke(link.object, event); + 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 { - link.getMethod().invoke(link.object, event); + 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); } @@ -65,23 +69,55 @@ public class AsyncEventLoop extends BaseEventLoop { 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); + 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 (notValidEventHandler(annotation, method)) + 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, preprocessors.remove(method.getName()))); + 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()) @@ -100,6 +136,7 @@ public class AsyncEventLoop extends BaseEventLoop { 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/EventPreprocessor.java b/event-loop/src/main/java/mc/core/events/async/EventPreprocessor.java index 905d661..107628a 100644 --- a/event-loop/src/main/java/mc/core/events/async/EventPreprocessor.java +++ b/event-loop/src/main/java/mc/core/events/async/EventPreprocessor.java @@ -8,5 +8,5 @@ import java.lang.annotation.*; @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface EventPreprocessor { - String eventName(); + String methodName(); } diff --git a/event-loop/src/test/java/ru/core/events/AsyncEventLoopTest.java b/event-loop/src/test/java/ru/core/events/AsyncEventLoopTest.java index 5d5f70d..f112174 100644 --- a/event-loop/src/test/java/ru/core/events/AsyncEventLoopTest.java +++ b/event-loop/src/test/java/ru/core/events/AsyncEventLoopTest.java @@ -17,6 +17,6 @@ public class AsyncEventLoopTest { asyncEventLoop.callEvent(testEvent); - Assert.assertEquals("Event handler was not called", "Hello from Async Event Handler!", testEvent.getDenyReason()); + Assert.assertEquals("Event handler was not called", "Hello! This is a message from Sync portion of the event", testEvent.getDenyReason()); } } diff --git a/event-loop/src/test/java/ru/core/events/handlers/AsyncEventHandler.java b/event-loop/src/test/java/ru/core/events/handlers/AsyncEventHandler.java index 634b9a1..371e0cf 100644 --- a/event-loop/src/test/java/ru/core/events/handlers/AsyncEventHandler.java +++ b/event-loop/src/test/java/ru/core/events/handlers/AsyncEventHandler.java @@ -1,18 +1,24 @@ package ru.core.events.handlers; +import lombok.extern.slf4j.Slf4j; import mc.core.events.EventHandler; import mc.core.events.LoginEvent; import mc.core.events.async.EventPreprocessor; +@Slf4j public class AsyncEventHandler { - @EventHandler - public void onLogin(LoginEvent event) { - event.setDenyReason("Hello from Async Event Handler!"); + @EventPreprocessor(methodName = "onLogin") + public void onLoginPreprocess(LoginEvent event) { + event.setDenyReason("Hello! This is a message from Async event preprocessor."); + + // Представим, что здесь мы выполнили запрос к БД + // и это значение - кол-во денег у игрока + /*return 20D;*/ } - @EventPreprocessor(eventName = "onLogin") - public void onLoginPreprocess(LoginEvent event) { - + @EventHandler + public void onLogin(LoginEvent event) { // money здесь будет равно тому, что вернул onLoginPreprocess + event.setDenyReason("Hello! This is a message from Sync portion of the event"); } }