mirror of
https://github.com/LamGC/ContentGrabbingJi.git
synced 2025-04-29 22:27:33 +00:00
[Add] Core 初步添加 Event 模块的具体实现和对 Message 的 Handler;
[Add] ThreadPoolEventExecutor, DefaultEventHandlerRegistry 添加基于线程池的事件执行器和事件处理注册器; [Add] MessageEventHandler 添加一个尚未完成的 MessageEvent 处理类;
This commit is contained in:
parent
a9b693a0a5
commit
3e34b3605b
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 LamGC
|
||||||
|
*
|
||||||
|
* ContentGrabbingJi is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* ContentGrabbingJi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.lamgc.cgj.bot.event;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认的事件处理注册器.
|
||||||
|
* @author LamGC
|
||||||
|
*/
|
||||||
|
public class DefaultEventHandlerRegistry implements EventHandlerRegistry {
|
||||||
|
|
||||||
|
private final Map<Method, Object> instanceMap = new Hashtable<>();
|
||||||
|
private final Map<Class<? extends EventObject>, Set<Method>> eventHandlerMap = new Hashtable<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int registerHandler(Object handlerObject) {
|
||||||
|
int count = 0;
|
||||||
|
Class<?> handlerClass = handlerObject.getClass();
|
||||||
|
Method[] methods = handlerClass.getDeclaredMethods();
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (!EventUtils.checkEventHandlerMethod(method)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addHandlerMethod(method, handlerObject);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addHandlerMethod(Method method, Object instance) {
|
||||||
|
instanceMap.put(method, instance);
|
||||||
|
Class<? extends EventObject> eventObjectClass = getParameterTypeClass(method);
|
||||||
|
if (!eventHandlerMap.containsKey(eventObjectClass)) {
|
||||||
|
eventHandlerMap.put(eventObjectClass, new CopyOnWriteArraySet<>());
|
||||||
|
}
|
||||||
|
eventHandlerMap.get(eventObjectClass).add(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<? extends EventObject> getParameterTypeClass(Method method) {
|
||||||
|
Class<?> parameterType = method.getParameterTypes()[0];
|
||||||
|
if (EventObject.class.isAssignableFrom(parameterType)) {
|
||||||
|
throw new IllegalArgumentException("Wrong parameter type: " + parameterType.getName());
|
||||||
|
}
|
||||||
|
return parameterType.asSubclass(EventObject.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Method, Object> getMatchedHandlerMethod(EventObject event) {
|
||||||
|
Map<Method, Object> result = new HashMap<>(0);
|
||||||
|
Set<Method> methods = findHandleMethod(event.getClass());
|
||||||
|
for (Method method : methods) {
|
||||||
|
result.put(method, instanceMap.get(method));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找可处理的方法.
|
||||||
|
* @param eventClass 事件 Class 对象.
|
||||||
|
* @return 返回存储了可处理方法的集合.
|
||||||
|
*/
|
||||||
|
private Set<Method> findHandleMethod(Class<? extends EventObject> eventClass) {
|
||||||
|
Set<Method> methods = new HashSet<>();
|
||||||
|
for (Class<? extends EventObject> clazz : eventHandlerMap.keySet()) {
|
||||||
|
if (!clazz.isAssignableFrom(eventClass)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Method> eventHandlers = eventHandlerMap.get(clazz);
|
||||||
|
for (Method handlerMethod : eventHandlers) {
|
||||||
|
EventHandler handlerInfo = handlerMethod.getAnnotation(EventHandler.class);
|
||||||
|
if (handlerInfo.inheritable()) {
|
||||||
|
methods.add(handlerMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 LamGC
|
||||||
|
*
|
||||||
|
* ContentGrabbingJi is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* ContentGrabbingJi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.lamgc.cgj.bot.event;
|
||||||
|
|
||||||
|
import net.lamgc.cgj.bot.framework.message.AbstractMessageEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息事件处理类.
|
||||||
|
* <p> 该类将接受原始消息事件, 经消息处理器处理后返回.
|
||||||
|
* @author LamGC
|
||||||
|
*/
|
||||||
|
public class MessageEventHandler {
|
||||||
|
|
||||||
|
@EventHandler(inheritable = true)
|
||||||
|
public void onHandle(AbstractMessageEvent event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 LamGC
|
||||||
|
*
|
||||||
|
* ContentGrabbingJi is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* ContentGrabbingJi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.lamgc.cgj.bot.event;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于线程池, 以事件为单位的异步事件执行器.
|
||||||
|
* <p> 以事件为单位对于 ContentGrabbingJi 来说是实现难度低, 还很合适的,
|
||||||
|
* ContentGrabbingJi 只会注册一个 Handler, 所以依然类似于一个 Handler 一个线程.
|
||||||
|
* @author LamGC
|
||||||
|
*/
|
||||||
|
public class ThreadPoolEventExecutor implements EventExecutor {
|
||||||
|
|
||||||
|
private final ThreadPoolExecutor threadExecutor;
|
||||||
|
private final EventHandlerRegistry registry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造线程池事件执行器.
|
||||||
|
* @param threadExecutor 执行器所使用的线程池.
|
||||||
|
* @param registry 事件处理注册器.
|
||||||
|
*/
|
||||||
|
public ThreadPoolEventExecutor(ThreadPoolExecutor threadExecutor, EventHandlerRegistry registry) {
|
||||||
|
this.threadExecutor = threadExecutor;
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(EventObject event) {
|
||||||
|
threadExecutor.execute(new ExecuteRunnable(event, registry.getMatchedHandlerMethod(event)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAsync() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按事件为单位的事件处理执行类.
|
||||||
|
*/
|
||||||
|
private final static class ExecuteRunnable implements Runnable {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(ExecuteRunnable.class);
|
||||||
|
|
||||||
|
private final EventObject event;
|
||||||
|
private final Map<Method, Object> handlerMethods;
|
||||||
|
|
||||||
|
private ExecuteRunnable(EventObject event, Map<Method, Object> handlerMethods) {
|
||||||
|
this.event = Objects.requireNonNull(event);
|
||||||
|
this.handlerMethods = Objects.requireNonNull(handlerMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (event instanceof Cancelable) {
|
||||||
|
runCancelableEvent();
|
||||||
|
} else {
|
||||||
|
runOrdinaryEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行可取消事件.
|
||||||
|
*/
|
||||||
|
private void runCancelableEvent() {
|
||||||
|
Cancelable cancelable = (Cancelable) event;
|
||||||
|
for (Method handlerMethod : handlerMethods.keySet()) {
|
||||||
|
if (cancelable.canceled()) {
|
||||||
|
log.warn("事件 {} 已取消, 终止处理.", event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object instance = handlerMethods.get(handlerMethod);
|
||||||
|
checkInstance(handlerMethod, instance);
|
||||||
|
handlerMethod.invoke(instance, event);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
log.error("Handler '" + handlerMethod.getDeclaringClass() + "." +
|
||||||
|
handlerMethod.getName() + "()'" +" throws an uncaught exception when handling an event",
|
||||||
|
e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception in handler '" + handlerMethod.getDeclaringClass() + "." +
|
||||||
|
handlerMethod.getName() + "()' call", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行普通事件.
|
||||||
|
*/
|
||||||
|
private void runOrdinaryEvent() {
|
||||||
|
handlerMethods.forEach((method, instance) -> {
|
||||||
|
try {
|
||||||
|
checkInstance(method, instance);
|
||||||
|
method.invoke(instance, event);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
log.error("Handler '" + method.getDeclaringClass() + "." + method.getName() + "()'" +
|
||||||
|
" throws an uncaught exception when handling an event", e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception in handler '" + method.getDeclaringClass() + "." +
|
||||||
|
method.getName() + "()' call", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkInstance(Method method, Object object) {
|
||||||
|
if (!method.getDeclaringClass().isAssignableFrom(object.getClass())) {
|
||||||
|
throw new ClassCastException("Method declaration class does not match call instance (Method: '" +
|
||||||
|
method.getDeclaringClass().getName() + "', Instance: '" + object.getClass().getName() + "')");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user