All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.enodeframework.infrastructure.impl.AbstractHandlerProvider.kt Maven / Gradle / Ivy

package org.enodeframework.infrastructure.impl

import org.enodeframework.annotation.Command
import org.enodeframework.annotation.Event
import org.enodeframework.annotation.Priority
import org.enodeframework.annotation.Subscribe
import org.enodeframework.common.exception.HandlerRegisterException
import org.enodeframework.common.extensions.ObjectContainer
import org.enodeframework.infrastructure.AssemblyInitializer
import org.enodeframework.infrastructure.MethodInvocation
import org.enodeframework.infrastructure.ObjectProxy
import org.enodeframework.messaging.MessageHandlerData
import org.reflections.ReflectionUtils
import org.slf4j.LoggerFactory
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import kotlin.reflect.jvm.kotlinFunction

abstract class AbstractHandlerProvider :
    AssemblyInitializer where THandlerProxyInterface : ObjectProxy, THandlerProxyInterface : MethodInvocation {
    private val handlerDict: MutableMap> = HashMap()
    private val messageHandlerDict: MutableMap> = HashMap()
    private val lookup = MethodHandles.lookup()

    private val logger = LoggerFactory.getLogger(this.javaClass)

    /**
     * handlerDict中注册的key
     */
    protected abstract fun getKey(method: Method): TKey

    /**
     * 代理执行的类型
     */
    protected abstract fun getHandlerProxyImplementationType(): Class

    /**
     * 判定执行类型是否匹配
     */
    protected abstract fun isHandlerSourceMatchKey(handlerSource: THandlerSource, key: TKey): Boolean

    /**
     * kotlin suspend 方法会多一个参数 kotlin.coroutines.Continuation
     */
    protected abstract fun isHandleMethodMatch(method: Method): Boolean

    /**
     * 在启动时校验一个消息是否可以注册多个处理器
     */
    protected abstract fun isHandleRegisterOnce(): Boolean

    /**
     * 是否是一个可挂起的方法
     */
    protected open fun isSuspendMethod(method: Method): Boolean {
        return method.kotlinFunction?.isSuspend == true
    }

    override fun initialize(objectContainer: ObjectContainer, componentTypes: Set>) {
        componentTypes.filter { type: Class<*> -> isHandlerType(type) }
            .forEach { handlerType: Class<*> -> registerHandler(objectContainer, handlerType) }
        initializeHandlerPriority()
    }

    fun getHandlersInternal(source: THandlerSource): List> {
        return messageHandlerDict.keys.filter { key: TKey -> isHandlerSourceMatchKey(source, key) }
            .map { key: TKey -> messageHandlerDict.getValue(key) }
    }

    private fun initializeHandlerPriority() {
        handlerDict.forEach { (key: TKey, handlers: List) ->
            val handlerData = MessageHandlerData()
            val listHandlers: MutableList = ArrayList()
            val queueHandlerDict: MutableMap = HashMap()
            handlers.forEach { handler: THandlerProxyInterface ->
                val priority = getHandleMethodPriority(handler)
                if (priority == 0) {
                    listHandlers.add(handler)
                } else {
                    queueHandlerDict[handler] = priority
                }
            }
            handlerData.allHandlers = handlers
            handlerData.listHandlers = listHandlers
            handlerData.queuedHandlers =
                queueHandlerDict.entries.sortedWith(Comparator.comparingInt { v -> v.value }).map { x -> x.key }
            messageHandlerDict[key] = handlerData
        }
    }

    private fun getHandleMethodPriority(handler: THandlerProxyInterface): Int {
        val method = handler.getMethod()
        var priority = 0
        val methodPriority = method.getAnnotation(Priority::class.java)
        if (methodPriority != null) {
            priority = methodPriority.value
        }
        if (priority == 0) {
            val classPriority = handler.getInnerObject().javaClass.getAnnotation(Priority::class.java)
            if (classPriority != null) {
                priority = classPriority.value
            }
        }
        return priority
    }

    private fun isHandlerType(type: Class<*>): Boolean {
        if (type.isInterface) {
            return false
        }
        return if (Modifier.isAbstract(type.modifiers)) {
            false
        } else containsHandleType(type)
    }

    private fun containsHandleType(type: Class<*>): Boolean {
        return type.isAnnotationPresent(Command::class.java) || type.isAnnotationPresent(Event::class.java)
    }

    protected fun isMethodAnnotationSubscribe(method: Method): Boolean {
        return method.isAnnotationPresent(Subscribe::class.java)
    }

    private fun registerHandler(objectContainer: ObjectContainer, handlerType: Class<*>) {
        val handleMethods = ReflectionUtils.getMethods(handlerType, { method: Method -> isHandleMethodMatch(method) })
        handleMethods.forEach { method: Method ->
            // 反射Method转换为MethodHandle,提高效率
            val handleMethod = lookup.findVirtual(
                handlerType, method.name, MethodType.methodType(method.returnType, method.parameterTypes)
            )
            val key = this.getKey(method)
            val handlers = handlerDict.computeIfAbsent(key) { ArrayList() }
            val handlerProxy = this.getHandlerProxyImplementationType().getDeclaredConstructor().newInstance()
            handlerProxy.setInnerObject(objectContainer.resolve(handlerType))
            handlerProxy.setMethod(method)
            handlerProxy.setMethodHandle(handleMethod)
            handlers.add(handlerProxy)
            // 针对command,只允许一个处理器
            if (isHandleRegisterOnce() && handlers.size > 1) {
                throw HandlerRegisterException("${method.name}#${method.parameterTypes.joinToString(",")}")
            }
            logger.info(
                "Handler register success. {} => {}",
                key,
                "${handlerType.name}#${method.name}#${method.parameterTypes.joinToString(",")}"
            )
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy