Removed legacy event loops
This commit is contained in:
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package mc.core.events;
|
|
||||||
|
|
||||||
public interface EventLoop {
|
|
||||||
void callEvent(Event event);
|
|
||||||
|
|
||||||
void addEventHandler(Object object);
|
|
||||||
}
|
|
||||||
@@ -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<Class<? extends Event>, List<ExecutorLink>> 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<? extends Event> 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<? extends Event> eventType = (Class<? extends Event>) method.getParameterTypes()[0];
|
|
||||||
|
|
||||||
List<SimpleEventLoop.ExecutorLink> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<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.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<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.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<? extends Event> eventType = (Class<? extends Event>) 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<ExecutorLink> 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<String, Method> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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<? extends Event> eventType = event.getClass();
|
|
||||||
|
|
||||||
if (handlers.containsKey(eventType)) {
|
|
||||||
// Create inter-thread state
|
|
||||||
List<ExecutorLink> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user