diff --git a/event-loop/src/main/java/mc/core/events/BaseEventLoop.java b/event-loop/src/main/java/mc/core/events/BaseEventLoop.java deleted file mode 100644 index 7945d61..0000000 --- a/event-loop/src/main/java/mc/core/events/BaseEventLoop.java +++ /dev/null @@ -1,34 +0,0 @@ -package mc.core.events; - -import lombok.extern.slf4j.Slf4j; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -@Slf4j -public abstract class BaseEventLoop implements EventLoop { - - protected boolean notValidEventHandler(EventHandler annotation, Method method) { - if (annotation == null) - return true; - - if (!Modifier.isPublic(method.getModifiers())) { - log.error("Unable to register {} as an EventHandler. Method must have a 'public' access modifier.", method.toString()); - return true; - - } - - if (method.getParameterCount() != 1) { - log.error("Unable to register {} as an EventHandler. Method must have exactly one argument.", method.toString()); - return true; - } - - 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()); - return true; - } - - return false; - } -} diff --git a/event-loop/src/main/java/mc/core/events/EventLoop.java b/event-loop/src/main/java/mc/core/events/EventLoop.java deleted file mode 100644 index 63fa506..0000000 --- a/event-loop/src/main/java/mc/core/events/EventLoop.java +++ /dev/null @@ -1,7 +0,0 @@ -package mc.core.events; - -public interface EventLoop { - void callEvent(Event event); - - void addEventHandler(Object object); -} diff --git a/event-loop/src/main/java/mc/core/events/SimpleEventLoop.java b/event-loop/src/main/java/mc/core/events/SimpleEventLoop.java deleted file mode 100644 index d93632e..0000000 --- a/event-loop/src/main/java/mc/core/events/SimpleEventLoop.java +++ /dev/null @@ -1,62 +0,0 @@ -package mc.core.events; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.*; - -@Slf4j -public class SimpleEventLoop extends BaseEventLoop { - private Map, List> handlers = new HashMap<>(); - - public SimpleEventLoop() { - log.warn("Warning! SimpleEventLoop doesn't support EventPreprocessors and DI. Code annotated @EventProcessor will not be executed at all."); - } - - @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; - 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) { - for (Method method : object.getClass().getDeclaredMethods()) { - EventHandler annotation = method.getAnnotation(EventHandler.class); - - if (notValidEventHandler(annotation, method)) - continue; - - @SuppressWarnings("unchecked") Class eventType = (Class) method.getParameterTypes()[0]; - - List eventHandlers = handlers.computeIfAbsent(eventType, s -> new ArrayList<>()); - eventHandlers.add(new SimpleEventLoop.ExecutorLink(annotation.priority().getValue(), annotation.ignoreCancelled(), method, object)); - eventHandlers.sort(Comparator.comparingInt(o -> o.priority)); - } - } - - /** - * 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; - } -} 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 deleted file mode 100644 index 9b8a4e2..0000000 --- a/event-loop/src/main/java/mc/core/events/async/AdvancedEventLoop.java +++ /dev/null @@ -1,145 +0,0 @@ -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 deleted file mode 100644 index 3145785..0000000 --- a/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java +++ /dev/null @@ -1,81 +0,0 @@ -package mc.core.events.async; - -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import mc.core.events.Event; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.concurrent.*; - -@Slf4j -public class AsyncEventLoop extends AdvancedEventLoop { - private static final double emaPeriod = (2D / (50D + 1D)); - private final ExecutorService preEventExecutor = new ThreadPoolExecutor(2, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); - @Getter - private double avgOverhead = 0; - - @Override - public void callEvent(Event event) { - long wholeMethodBenchmark = System.nanoTime(); - long asyncExecutionWaitTime = 0, syncExecutionTime = 0, tempTime; - Class eventType = event.getClass(); - - if (handlers.containsKey(eventType)) { - // Create inter-thread state - List handlerList = handlers.get(eventType); - EventBatch eventBatch = new EventBatch(handlerList.size()); - CountDownLatch latch = new CountDownLatch(handlerList.size()); - - // Submit all defined preprocessing methods as async tasks - for (int i = 0; i < handlerList.size(); i++) { - if (handlerList.get(i).getPreprocessMethod() == null) { - // We have already "allocated" a space for this task in CountDownLatch, - // but since there is no actual preprocess method defined for this handler - // we just skip it by ticking the latch down manually - latch.countDown(); - } else { - preEventExecutor.submit(new PreprocessTask(i, eventBatch, latch, handlerList.get(i), event)); - } - } - - // Await for them to complete - tempTime = System.nanoTime(); - try { - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - asyncExecutionWaitTime = System.nanoTime() - tempTime; - - // Synchronously invoke EventHandlers with - // data obtained from EventBatch - for (int i = 0; i < handlerList.size(); i++) { - ExecutorLink link = handlerList.get(i); - if (!link.isIgnoreCancelled() || !event.isCanceled()) { - try { - tempTime = System.nanoTime(); - if (link.getResultInjection() != null) - link.getMethod().invoke(link.getObject(), event, eventBatch.getInjectionObject(i)); - else - link.getMethod().invoke(link.getObject(), event); - syncExecutionTime += System.nanoTime() - tempTime; - } catch (IllegalAccessException | InvocationTargetException e) { - log.error("Exception caught while attempting to dispatch {}.", eventType.getSimpleName(), e); - } - } - } - } - - wholeMethodBenchmark = System.nanoTime() - wholeMethodBenchmark; - long overhead = wholeMethodBenchmark - asyncExecutionWaitTime - syncExecutionTime; - - // Now we calculate exponential moving average of - // overhead timings - if (avgOverhead == 0) - avgOverhead = overhead; - else - avgOverhead = (overhead - avgOverhead) * emaPeriod + avgOverhead; - } -} - diff --git a/event-loop/src/main/java/mc/core/events/async/EventBatch.java b/event-loop/src/main/java/mc/core/events/async/EventBatch.java deleted file mode 100644 index 7a6d35d..0000000 --- a/event-loop/src/main/java/mc/core/events/async/EventBatch.java +++ /dev/null @@ -1,22 +0,0 @@ -package mc.core.events.async; - -/** - * Stores state to pass from async executors to sync - * - * TODO: Change name, misleading - */ -public class EventBatch { - private Object[] returnInject; - - public EventBatch(int size) { - this.returnInject = new Object[size]; - } - - public Object getInjectionObject(int id) { - return returnInject[id]; - } - - public void setInjectionObject(int id, Object value) { - returnInject[id] = value; - } -} 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 deleted file mode 100644 index 107628a..0000000 --- a/event-loop/src/main/java/mc/core/events/async/EventPreprocessor.java +++ /dev/null @@ -1,12 +0,0 @@ -package mc.core.events.async; - - -import java.lang.annotation.*; - -@Documented -@Target(ElementType.METHOD) -@Inherited -@Retention(RetentionPolicy.RUNTIME) -public @interface EventPreprocessor { - String methodName(); -} diff --git a/event-loop/src/main/java/mc/core/events/async/PreprocessTask.java b/event-loop/src/main/java/mc/core/events/async/PreprocessTask.java deleted file mode 100644 index e38a8c3..0000000 --- a/event-loop/src/main/java/mc/core/events/async/PreprocessTask.java +++ /dev/null @@ -1,32 +0,0 @@ -package mc.core.events.async; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import mc.core.events.Event; - -import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.CountDownLatch; - -@RequiredArgsConstructor -@Slf4j -public class PreprocessTask implements Runnable { - private final int id; - private final EventBatch eventBatch; - private final CountDownLatch latch; - private final AsyncEventLoop.ExecutorLink link; - private final Event event; - - @Override - public void run() { - try { - Object result = link.getPreprocessMethod().invoke(link.getObject(), event); - if (result != null) - eventBatch.setInjectionObject(id, result); - } catch (IllegalAccessException | InvocationTargetException e) { - log.error("Exception caught while attempting to run event preprocessing.", e); - } finally { - latch.countDown(); - } - - } -} diff --git a/event-loop/src/test/java/ru/core/events/AsyncEventLoopBenchmark.java b/event-loop/src/test/java/ru/core/events/AsyncEventLoopBenchmark.java deleted file mode 100644 index 193fc6f..0000000 --- a/event-loop/src/test/java/ru/core/events/AsyncEventLoopBenchmark.java +++ /dev/null @@ -1,47 +0,0 @@ -package ru.core.events; - -import com.carrotsearch.junitbenchmarks.AbstractBenchmark; -import com.carrotsearch.junitbenchmarks.BenchmarkOptions; -import mc.core.events.LoginEvent; -import mc.core.events.async.AdvancedEventLoop; -import mc.core.events.async.AsyncEventLoop; -import org.junit.BeforeClass; -import org.junit.Test; -import ru.core.events.handlers.AsyncEventHandler; - -public class AsyncEventLoopBenchmark extends AbstractBenchmark { - private static final int ITERATIONS = 200; - private static AsyncEventLoop asyncEventLoop; - private static AdvancedEventLoop advancedEventLoop; - private static LoginEvent testEvent; - - @BeforeClass - public static void setup() { - asyncEventLoop = new AsyncEventLoop(); - asyncEventLoop.addEventHandler(new AsyncEventHandler()); - asyncEventLoop.addEventHandler(new AsyncEventHandler()); - asyncEventLoop.addEventHandler(new AsyncEventHandler()); - advancedEventLoop = new AdvancedEventLoop(); - advancedEventLoop.addEventHandler(new AsyncEventHandler()); - advancedEventLoop.addEventHandler(new AsyncEventHandler()); - advancedEventLoop.addEventHandler(new AsyncEventHandler()); - testEvent = new LoginEvent(null); - testEvent.setDenyReason("none"); - } - - @Test - @BenchmarkOptions(warmupRounds = 5, benchmarkRounds = 15) - public void async() { - for (int i = 0; i < ITERATIONS; i++) { - asyncEventLoop.callEvent(testEvent); - } - } - - @Test - @BenchmarkOptions(warmupRounds = 5, benchmarkRounds = 15) - public void advanced() { - for (int i = 0; i < ITERATIONS; i++) { - advancedEventLoop.callEvent(testEvent); - } - } -} diff --git a/event-loop/src/test/java/ru/core/events/AsyncEventLoopTest.java b/event-loop/src/test/java/ru/core/events/AsyncEventLoopTest.java deleted file mode 100644 index f112174..0000000 --- a/event-loop/src/test/java/ru/core/events/AsyncEventLoopTest.java +++ /dev/null @@ -1,22 +0,0 @@ -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! This is a message from Sync portion of the event", testEvent.getDenyReason()); - } -} diff --git a/event-loop/src/test/java/ru/core/events/SimpleEventLoopBenchmark.java b/event-loop/src/test/java/ru/core/events/SimpleEventLoopBenchmark.java deleted file mode 100644 index 7fc0a9e..0000000 --- a/event-loop/src/test/java/ru/core/events/SimpleEventLoopBenchmark.java +++ /dev/null @@ -1,30 +0,0 @@ -package ru.core.events; - -import com.carrotsearch.junitbenchmarks.AbstractBenchmark; -import com.carrotsearch.junitbenchmarks.BenchmarkOptions; -import mc.core.events.LoginEvent; -import mc.core.events.SimpleEventLoop; -import org.junit.BeforeClass; -import org.junit.Test; -import ru.core.events.handlers.SampleEventHandler; - -public class SimpleEventLoopBenchmark extends AbstractBenchmark { - private static SimpleEventLoop simpleEventLoop; - private static LoginEvent testEvent; - - @BeforeClass - public static void setup(){ - simpleEventLoop = new SimpleEventLoop(); - simpleEventLoop.addEventHandler(new SampleEventHandler()); - testEvent = new LoginEvent(null); - testEvent.setDenyReason("none"); - } - - @Test - @BenchmarkOptions(warmupRounds = 5, benchmarkRounds = 15) - public void benchmark() { - for (int i = 0; i < 50_000_000; i++) { - simpleEventLoop.callEvent(testEvent); - } - } -} diff --git a/event-loop/src/test/java/ru/core/events/SimpleEventLoopTest.java b/event-loop/src/test/java/ru/core/events/SimpleEventLoopTest.java deleted file mode 100644 index 4429def..0000000 --- a/event-loop/src/test/java/ru/core/events/SimpleEventLoopTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package ru.core.events; - -import mc.core.events.LoginEvent; -import mc.core.events.SimpleEventLoop; -import org.junit.Assert; -import org.junit.Test; -import ru.core.events.handlers.HelloWorldSimpleEventHandler; - -public class SimpleEventLoopTest { - - @Test - public void loopWorks() { - SimpleEventLoop simpleEventLoop = new SimpleEventLoop(); - simpleEventLoop.addEventHandler(new HelloWorldSimpleEventHandler()); - LoginEvent testEvent = new LoginEvent(null); - testEvent.setDenyReason("none"); - - simpleEventLoop.callEvent(testEvent); - - Assert.assertEquals("Event handler was not called", "Hello from SampleEventHandler!", 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 deleted file mode 100644 index d2891ad..0000000 --- a/event-loop/src/test/java/ru/core/events/handlers/AsyncEventHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -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 { - - @EventPreprocessor(methodName = "onLogin") - public void onLoginPreprocess(LoginEvent event) { - event.setDenyReason("Hello! This is a message from Async event preprocessor."); - - try { - Thread.sleep(1); - } catch (InterruptedException e) { - e.printStackTrace(); - } - // Представим, что здесь мы выполнили запрос к БД - // и это значение - кол-во денег у игрока - /*return 20D;*/ - } - - @EventHandler - public void onLogin(LoginEvent event) { // money здесь будет равно тому, что вернул onLoginPreprocess - event.setDenyReason("Hello! This is a message from Sync portion of the event"); - } -} diff --git a/event-loop/src/test/java/ru/core/events/handlers/FastEventHandler.java b/event-loop/src/test/java/ru/core/events/handlers/FastEventHandler.java deleted file mode 100644 index 733180d..0000000 --- a/event-loop/src/test/java/ru/core/events/handlers/FastEventHandler.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.core.events.handlers; - -import mc.core.events.EventHandler; -import mc.core.events.LoginEvent; - -public class FastEventHandler { - @EventHandler - public void onPlayerLogin(LoginEvent event) { - - } -} diff --git a/event-loop/src/test/java/ru/core/events/handlers/HelloWorldSimpleEventHandler.java b/event-loop/src/test/java/ru/core/events/handlers/HelloWorldSimpleEventHandler.java deleted file mode 100644 index 640e944..0000000 --- a/event-loop/src/test/java/ru/core/events/handlers/HelloWorldSimpleEventHandler.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.core.events.handlers; - -import mc.core.events.EventHandler; -import mc.core.events.LoginEvent; - -public class HelloWorldSimpleEventHandler { - @EventHandler - public void onPlayerLogin(LoginEvent event) { - event.setDenyReason("Hello from SampleEventHandler!"); - } -} diff --git a/event-loop/src/test/java/ru/core/events/handlers/SampleEventHandler.java b/event-loop/src/test/java/ru/core/events/handlers/SampleEventHandler.java deleted file mode 100644 index 36a7ec4..0000000 --- a/event-loop/src/test/java/ru/core/events/handlers/SampleEventHandler.java +++ /dev/null @@ -1,20 +0,0 @@ -package ru.core.events.handlers; - -import mc.core.events.EventHandler; -import mc.core.events.LoginEvent; - -public class SampleEventHandler { - @EventHandler - public void onPlayerLogin(LoginEvent event) { - event.setDenyReason("Hello from SampleEventHandler!"); - } - - public void notHandler(LoginEvent event){ - - } - - @EventHandler - public void invalidParam(Object object){ - - } -}