diff --git a/surf-cloud-api/surf-cloud-api-common/api/surf-cloud-api-common.api b/surf-cloud-api/surf-cloud-api-common/api/surf-cloud-api-common.api index b27b141c..559c4125 100644 --- a/surf-cloud-api/surf-cloud-api-common/api/surf-cloud-api-common.api +++ b/surf-cloud-api/surf-cloud-api-common/api/surf-cloud-api-common.api @@ -254,10 +254,7 @@ public abstract interface annotation class dev/slne/surf/cloud/api/common/meta/S } public abstract interface annotation class dev/slne/surf/cloud/api/common/meta/SurfNettyPacketHandler : java/lang/annotation/Annotation { - public abstract fun classes ()[Ljava/lang/Class; - public abstract fun condition ()Ljava/lang/String; public abstract fun id ()Ljava/lang/String; - public abstract fun value ()[Ljava/lang/Class; } public abstract interface class dev/slne/surf/cloud/api/common/netty/NettyClient { @@ -1237,17 +1234,14 @@ public final class dev/slne/surf/cloud/api/common/netty/packet/NettyPacket$Compa } public final class dev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo { - public static final synthetic fun box-impl (Ldev/slne/surf/cloud/api/common/netty/network/Connection;)Ldev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo; - public static fun constructor-impl (Ldev/slne/surf/cloud/api/common/netty/network/Connection;)Ldev/slne/surf/cloud/api/common/netty/network/Connection; + public fun (Ldev/slne/surf/cloud/api/common/netty/network/Connection;)V + public final fun component1 ()Ldev/slne/surf/cloud/api/common/netty/network/Connection; + public final fun copy (Ldev/slne/surf/cloud/api/common/netty/network/Connection;)Ldev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo; + public static synthetic fun copy$default (Ldev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo;Ldev/slne/surf/cloud/api/common/netty/network/Connection;ILjava/lang/Object;)Ldev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo; public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl (Ldev/slne/surf/cloud/api/common/netty/network/Connection;Ljava/lang/Object;)Z - public static final fun equals-impl0 (Ldev/slne/surf/cloud/api/common/netty/network/Connection;Ldev/slne/surf/cloud/api/common/netty/network/Connection;)Z public final fun getOrigin ()Ldev/slne/surf/cloud/api/common/netty/network/Connection; public fun hashCode ()I - public static fun hashCode-impl (Ldev/slne/surf/cloud/api/common/netty/network/Connection;)I public fun toString ()Ljava/lang/String; - public static fun toString-impl (Ldev/slne/surf/cloud/api/common/netty/network/Connection;)Ljava/lang/String; - public final synthetic fun unbox-impl ()Ldev/slne/surf/cloud/api/common/netty/network/Connection; } public final class dev/slne/surf/cloud/api/common/netty/packet/Packet_extensionKt { diff --git a/surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/meta/SurfNettyPacketHandler.kt b/surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/meta/SurfNettyPacketHandler.kt index ac05f122..01b16f3e 100644 --- a/surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/meta/SurfNettyPacketHandler.kt +++ b/surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/meta/SurfNettyPacketHandler.kt @@ -1,8 +1,6 @@ package dev.slne.surf.cloud.api.common.meta import org.springframework.aot.hint.annotation.Reflective -import org.springframework.core.annotation.AliasFor -import kotlin.reflect.KClass /** * Annotation for marking methods in a component as packet handlers. @@ -17,8 +15,5 @@ import kotlin.reflect.KClass ) @Reflective annotation class SurfNettyPacketHandler( - @get:AliasFor("classes") val value: Array> = [], - @get:AliasFor("values") val classes: Array> = [], - val condition: String = "", val id: String = "" ) diff --git a/surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo.kt b/surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo.kt index 6a023a30..6dc1c3bc 100644 --- a/surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo.kt +++ b/surf-cloud-api/surf-cloud-api-common/src/main/kotlin/dev/slne/surf/cloud/api/common/netty/packet/NettyPacketInfo.kt @@ -2,5 +2,4 @@ package dev.slne.surf.cloud.api.common.netty.packet import dev.slne.surf.cloud.api.common.netty.network.Connection -@JvmInline -value class NettyPacketInfo(val origin: Connection) \ No newline at end of file +data class NettyPacketInfo(val origin: Connection) \ No newline at end of file diff --git a/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/NettyListenerRegistry.kt b/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/NettyListenerRegistry.kt index 378b0685..96bc360e 100644 --- a/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/NettyListenerRegistry.kt +++ b/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/NettyListenerRegistry.kt @@ -6,14 +6,11 @@ import dev.slne.surf.cloud.api.common.netty.packet.NettyPacketInfo import dev.slne.surf.cloud.api.common.util.isSuspending import dev.slne.surf.cloud.api.common.util.mutableObject2ObjectMapOf import it.unimi.dsi.fastutil.objects.Object2ObjectFunction -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import it.unimi.dsi.fastutil.objects.ObjectSet import java.lang.reflect.Method import java.lang.reflect.Modifier import kotlin.coroutines.Continuation -import kotlin.jvm.java -import kotlin.reflect.jvm.kotlinFunction object NettyListenerRegistry { private val listeners = diff --git a/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/RegisteredListener.kt b/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/RegisteredListener.kt index 68598b7e..a7c560a4 100644 --- a/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/RegisteredListener.kt +++ b/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/RegisteredListener.kt @@ -3,8 +3,6 @@ package dev.slne.surf.cloud.core.common.netty.registry.listener import dev.slne.surf.cloud.api.common.netty.exception.SurfNettyListenerRegistrationException import dev.slne.surf.cloud.api.common.netty.packet.NettyPacket import dev.slne.surf.cloud.api.common.netty.packet.NettyPacketInfo -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext import tech.hiddenproject.aide.reflection.LambdaWrapperHolder import tech.hiddenproject.aide.reflection.annotation.Invoker import java.lang.reflect.Method @@ -49,35 +47,32 @@ class RegisteredListener( } } - suspend fun handle(packet: NettyPacket, info: NettyPacketInfo) = - withContext(Dispatchers.IO) { - when (invokerType) { - InvokerType.ONE_PARAM -> { - if (suspending) { - (invoker as RegisteredListenerSuspendInvoker1).handle(bean, packet) - } else { - (invoker as RegisteredListenerInvoker1).handle(bean, packet) - } - } - - InvokerType.TWO_PARAMS -> { - if (suspending) { - (invoker as RegisteredListenerSuspendInvoker2).handle(bean, packet, info) - } else { - (invoker as RegisteredListenerInvoker2).handle(bean, packet, info) - } - } - - InvokerType.TWO_PARAMS_REVERSED -> { - if (suspending) { - (invoker as RegisteredListenerSuspendInvoker2Rev).handle(bean, info, packet) - } else { - (invoker as RegisteredListenerInvoker2Rev).handle(bean, info, packet) - } - } + suspend fun handle(packet: NettyPacket, info: NettyPacketInfo) = when (invokerType) { + InvokerType.ONE_PARAM -> { + if (suspending) { + (invoker as RegisteredListenerSuspendInvoker1).handle(bean, packet) + } else { + (invoker as RegisteredListenerInvoker1).handle(bean, packet) + } + } + + InvokerType.TWO_PARAMS -> { + if (suspending) { + (invoker as RegisteredListenerSuspendInvoker2).handle(bean, packet, info) + } else { + (invoker as RegisteredListenerInvoker2).handle(bean, packet, info) } } + InvokerType.TWO_PARAMS_REVERSED -> { + if (suspending) { + (invoker as RegisteredListenerSuspendInvoker2Rev).handle(bean, info, packet) + } else { + (invoker as RegisteredListenerInvoker2Rev).handle(bean, info, packet) + } + } + } + private enum class InvokerType { ONE_PARAM, TWO_PARAMS, diff --git a/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/processor/NettyListenerRegistryProcessor.kt b/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/processor/NettyListenerRegistryProcessor.kt index cd00ccba..00d6920c 100644 --- a/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/processor/NettyListenerRegistryProcessor.kt +++ b/surf-cloud-core/surf-cloud-core-common/src/main/kotlin/dev/slne/surf/cloud/core/common/netty/registry/listener/processor/NettyListenerRegistryProcessor.kt @@ -1,57 +1,13 @@ package dev.slne.surf.cloud.core.common.netty.registry.listener.processor import dev.slne.surf.cloud.api.common.netty.exception.SurfNettyListenerRegistrationException -import dev.slne.surf.cloud.api.common.netty.packet.NettyPacket -import dev.slne.surf.cloud.api.common.netty.packet.NettyPacketInfo import dev.slne.surf.cloud.api.common.util.* import dev.slne.surf.cloud.core.common.netty.registry.listener.NettyListenerRegistry -import dev.slne.surf.surfapi.core.api.util.logger -import it.unimi.dsi.fastutil.objects.ObjectList -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import org.reactivestreams.Subscriber -import org.reactivestreams.Subscription import org.springframework.aop.framework.AopInfrastructureBean -import org.springframework.aop.framework.autoproxy.AutoProxyUtils -import org.springframework.aop.scope.ScopedObject -import org.springframework.aop.scope.ScopedProxyUtils -import org.springframework.aop.support.AopUtils import org.springframework.beans.factory.BeanCreationException -import org.springframework.beans.factory.SmartInitializingSingleton -import org.springframework.beans.factory.config.BeanFactoryPostProcessor import org.springframework.beans.factory.config.BeanPostProcessor -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory -import org.springframework.beans.factory.getBeanNamesForType -import org.springframework.beans.factory.getBeansOfType -import org.springframework.context.ApplicationContext -import org.springframework.context.ApplicationContextAware -import org.springframework.context.ConfigurableApplicationContext -import org.springframework.context.expression.AnnotatedElementKey -import org.springframework.context.expression.BeanFactoryResolver -import org.springframework.context.expression.CachedExpressionEvaluator -import org.springframework.context.expression.MethodBasedEvaluationContext -import org.springframework.core.* -import org.springframework.core.MethodIntrospector.MetadataLookup -import org.springframework.core.annotation.AnnotatedElementUtils -import org.springframework.core.annotation.AnnotationAwareOrderComparator -import org.springframework.core.annotation.AnnotationUtils -import org.springframework.core.annotation.Order -import org.springframework.expression.EvaluationContext -import org.springframework.expression.Expression -import org.springframework.expression.spel.support.StandardEvaluationContext import org.springframework.stereotype.Component -import org.springframework.util.ClassUtils -import org.springframework.util.ReflectionUtils -import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method -import java.lang.reflect.Proxy -import java.lang.reflect.UndeclaredThrowableException -import java.util.concurrent.CompletionStage -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.contract -import kotlin.coroutines.CoroutineContext import dev.slne.surf.cloud.api.common.meta.SurfNettyPacketHandler as Handler @@ -80,577 +36,4 @@ class NettyListenerRegistryProcessor : BeanPostProcessor { throw BeanCreationException(beanName, e.message ?: "", e) } } -} - -class Test : SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor { - private var context: ConfigurableApplicationContext? = null - private var beanFactory: ConfigurableListableBeanFactory? = null - private var eventListenerFactories: ObjectList? = null - - private val originalEvaluationContext = StandardEvaluationContext() - private val evaluator = NettyEventExpressionEvaluator(originalEvaluationContext) - - private val nonAnnotatedClasses = mutableObjectSetOf>() - - override fun setApplicationContext(applicationContext: ApplicationContext) { - require(applicationContext is ConfigurableApplicationContext) { "ApplicationContext must be ConfigurableApplicationContext" } - context = applicationContext - } - - override fun postProcessBeanFactory(beanFactory: ConfigurableListableBeanFactory) { - this.beanFactory = beanFactory - this.originalEvaluationContext.setBeanResolver(BeanFactoryResolver(beanFactory)) - - val beans = beanFactory.getBeansOfType( - includeNonSingletons = false, - allowEagerInit = false - ) - - val elements = beans.values.toTypedArray() - AnnotationAwareOrderComparator.sort(elements) - eventListenerFactories = objectListOf(*elements) - } - - override fun afterSingletonsInstantiated() { - val beanFactory = this.beanFactory ?: error("No ConfigurableListableBeanFactory set") - val beanNames = beanFactory.getBeanNamesForType() - - for (name in beanNames) { - if (ScopedProxyUtils.isScopedTarget(name)) continue - var type = - runCatching { AutoProxyUtils.determineTargetClass(beanFactory, name) }.getOrNull() - ?: continue - - if (ScopedObject::class.java.isAssignableFrom(type)) { - runCatching { - val targetClass = AutoProxyUtils.determineTargetClass( - beanFactory, - ScopedProxyUtils.getTargetBeanName(name) - ) - if (targetClass != null) { - type = targetClass - } - } - } - - try { - processBean(name, type) - } catch (e: Throwable) { - throw BeanCreationException( - "Failed to process @${Handler::class.simpleName} annotation on bean with name '$name': ${e.message}", - e - ) - } - } - } - - private fun processBean(beanName: String, targetType: Class<*>) { - if (this.nonAnnotatedClasses.contains(targetType)) return - if (!AnnotationUtils.isCandidateClass(targetType, Handler::class.java)) return - if (isSpringContainerClass(targetType)) return - - var annotatedMethods = runCatching { - MethodIntrospector.selectMethods( - targetType, - MetadataLookup { - AnnotatedElementUtils.findMergedAnnotation( - it, - Handler::class.java - ) - } - ) - }.getOrNull() - - if (annotatedMethods.isNullOrEmpty()) { - nonAnnotatedClasses.add(targetType) - } else { - val context = this.context ?: error("No ConfigurableApplicationContext set") - val factories = eventListenerFactories ?: error("No NettyListenerFactory beans found") - - for (method in annotatedMethods.keys) { - for (factory in factories) { - if (factory.supportsMethod(method)) { - val methodToUse = - AopUtils.selectInvocableMethod(method, context.getType(beanName)) - val listener = - factory.createApplicationListener(beanName, targetType, methodToUse) - dev.slne.surf.cloud.core.common.netty.registry.listener.processor.NettyListenerRegistry.registerListener( - listener - ) - break - } - } - } - } - } - - companion object { - - /** - * Determine whether the given class is an {@code org.springframework} - * bean class that is not annotated as a user or test {@link Component}... - * which indicates that there is no {@link EventListener} to be found there. - */ - private fun isSpringContainerClass(clazz: Class<*>): Boolean = - clazz.getName().startsWith("org.springframework.") - && !AnnotatedElementUtils.isAnnotated( - ClassUtils.getUserClass(clazz), Component::class.java - ) - } -} - -interface NettyListenerFactory { - fun supportsMethod(method: Method): Boolean - fun createApplicationListener( - beanName: String, - type: Class<*>, - method: Method - ): NettyListener<*> -} - -@Component -class DefaultNettyListenerFactory : NettyListenerFactory, Ordered { - private var order = Ordered.LOWEST_PRECEDENCE - - fun setOrder(order: Int) { - this.order = order - } - - override fun getOrder(): Int { - return order - } - - override fun supportsMethod(method: Method): Boolean { - return true - } - - override fun createApplicationListener( - beanName: String, - type: Class<*>, - method: Method - ): NettyListener<*> { - return NettyListenerMethodAdapter(beanName, type, method) - } -} - -interface NettyListener

{ - suspend fun onPacket(packet: P) -} - -interface SmartNettyListener : NettyListener, Ordered { - val listenerId: String - get() = "" - - fun supportsPacketType(type: Class<*>): Boolean - - fun supportsSourceType(sourceType: Class<*>?): Boolean { - return true - } - - override fun getOrder(): Int { - return Ordered.LOWEST_PRECEDENCE - } -} - -interface GenericNettyListener : SmartNettyListener { - override fun supportsPacketType(type: Class<*>): Boolean { - return supportsPacketType(ResolvableType.forClass(type)) - } - - fun supportsPacketType(type: ResolvableType): Boolean -} - -class NettyListenerMethodAdapter( - private val beanName: String, - targetClass: Class<*>, - method: Method -) : GenericNettyListener { - - private val method = BridgeMethodResolver.findBridgedMethod(method) - private val targetMethod = if (!Proxy.isProxyClass(targetClass)) AopUtils.getMostSpecificMethod( - method, - targetClass - ) else method - private val methodKey = AnnotatedElementKey(targetMethod, targetClass) - - private val annotation = - AnnotatedElementUtils.findMergedAnnotation(targetMethod, Handler::class.java) - - private val declaredEventTypes = resolveDeclaredPacketTypes(method, annotation) - private val condition = annotation?.condition - private val order = resolveOrder(method) - - @Volatile - private var _listenerId: String? - - private var applicationContext: ApplicationContext? = null - private var evaluator: NettyEventExpressionEvaluator? = null - - private val coroutineContext: CoroutineContext by lazy { - Dispatchers.Default + CoroutineName("netty-packet-handler-${listenerId}") + SupervisorJob() + CoroutineExceptionHandler { _, throwable -> - log.atSevere() - .withCause(throwable) - .log("Unhandled exception in NettyListener method") - } - } - - override val listenerId: String - get() { - var id = this._listenerId - if (id == null) { - id = getDefaultListenerId() - this._listenerId = id - } - return id - } - - init { - val id = annotation?.id ?: "" - _listenerId = if (id.isNotEmpty()) id else null - } - - fun init(applicationContext: ApplicationContext, evaluator: NettyEventExpressionEvaluator) { - this.applicationContext = applicationContext - this.evaluator = evaluator - } - - override suspend fun onPacket(packet: NettyPacket) { - processPacket(packet) - } - - override fun supportsPacketType(type: ResolvableType): Boolean { - for (declaredType in declaredEventTypes) { - if (if (type.hasUnresolvableGenerics()) declaredType.toClass() - .isAssignableFrom(type.toClass()) else declaredType.isAssignableFrom(type) - ) { - return true - } - } - - return false - } - - override fun supportsPacketType(type: Class<*>): Boolean { - return true - } - - override fun supportsSourceType(sourceType: Class<*>?): Boolean { - return true - } - - override fun getOrder(): Int { - return order - } - - fun getDefaultListenerId(): String { - val method = targetMethod - val joinedParams = method.parameterTypes.joinToString( - separator = ",", - prefix = "(", - postfix = ")" - ) { it.name } - - return ClassUtils.getQualifiedMethodName(method) + joinedParams - } - - fun processPacket(packet: NettyPacket) { - val args = resolveArguments(packet) - if (shouldHandle(packet, args)) { - val result = doInvoke(args) - if (result != null) { - handleResult(result) - } - } - } - - fun shouldHandle(packet: NettyPacket): Boolean { - return shouldHandle(packet, resolveArguments(packet)) - } - - @OptIn(ExperimentalContracts::class) - private fun shouldHandle(packet: NettyPacket, args: Array?): Boolean { - contract { - returns(true) implies (args != null) - } - - if (args == null) return false - val condition = condition - - if (!condition.isNullOrBlank()) { - val evaluator = this.evaluator ?: error("No NettyEventExpressionEvaluator set") - return evaluator.condition(condition, packet, this.targetMethod, this.methodKey, args) - } - - return true - } - - private fun resolveArguments(packet: NettyPacket): Array? { - getResolvableType(packet) ?: return null - - if (method.parameterCount == 0) { - return arrayOf() - } - - return arrayOf(packet) - } - - private fun handleResult(result: Any) { - if (ReactiveResultHandler().subscribeToPublisher(result)) { - return - } else if(result is CompletionStage<*>) { - result.whenComplete { returnValue, ex -> - if (ex != null) { - log.atSevere().withCause(ex).log("Error in NettyListener method") - } else { - if (returnValue != null && returnValue !is Unit) { - error("Unexpected return value from NettyListener method. Expected Unit, got $returnValue") - } - } - } - } - } - - private fun doInvoke(args: Array): Any? { - val bean = getTargetBean() - if (bean == null) { - return null - } - - ReflectionUtils.makeAccessible(this.method) - - try { - if (KotlinDetector.isSuspendingFunction(this.method)) { - return CoroutinesUtils.invokeSuspendingFunction( - coroutineContext, - this.method, - bean, - args - ) - } - - return this.method.invoke(bean, *args) - } catch (ex: IllegalArgumentException) { - assertTargetBean(this.method, bean, args) - throw IllegalStateException(getInvocationErrorMessage(bean, ex.message, args)) - } catch (ex: IllegalAccessException) { - throw IllegalStateException(getInvocationErrorMessage(bean, ex.message, args)) - } catch (ex: InvocationTargetException) { - val targetException = ex.targetException - if (targetException is RuntimeException) { - throw targetException - } - val msg = - getInvocationErrorMessage(bean, "Failed to invoke packet listener method", args) - throw UndeclaredThrowableException(targetException, msg) - } - } - - private fun getTargetBean(): Any? { - val applicationContext = this.applicationContext ?: error("No ApplicationContext set") - return applicationContext.getBean(this.beanName) - } - - private fun getDetailedErrorMessage(bean: Any, message: String?): String { - return buildString { - if (message?.isNotEmpty() == true) { - append(message) - appendLine() - } - append("HandlerMethod details: ") - appendLine() - append("Bean [${bean.javaClass.name}]") - appendLine() - append("Method [${method.toGenericString()}]") - appendLine() - } - } - - - private fun assertTargetBean(method: Method, targetBean: Any, args: Array) { - val methodDeclaringClass = method.declaringClass - val targetBeanClass: Class<*> = targetBean.javaClass - if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) { - val msg = buildString { - append("The packet listener method class '") - append(methodDeclaringClass.getName()) - append("' is not an instance of the actual bean class '") - append(targetBeanClass.getName()) - append("'. If the bean requires proxying ") - append("(for example, due to @Transactional), please use class-based proxying.") - } - - throw IllegalStateException(getInvocationErrorMessage(targetBean, msg, args)) - } - } - - private fun getInvocationErrorMessage( - bean: Any, - message: String?, - resolvedArgs: Array - ): String { - return buildString { - append(getDetailedErrorMessage(bean, message)) - append("Resolved arguments:") - appendLine() - - for ((i, value) in resolvedArgs.withIndex()) { - append("[$i] ") - if (value == null) { - append("[null]") - } else { - append("[type=${value.javaClass.name}] ") - append("[value=$value]") - } - appendLine() - } - } - } - - private fun getResolvableType(packet: NettyPacket): ResolvableType? { - for (declaredType in declaredEventTypes) { - val packetClass = declaredType.toClass() - if (packetClass.isInstance(packet)) { - return declaredType - } - } - return null - } - - private inner class ReactiveResultHandler { - fun subscribeToPublisher(result: Any): Boolean { - val adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(result.javaClass) - if (adapter != null) { - adapter.toPublisher(result).subscribe(PacketListenerPublicationSubscriber()) - return true - } - - return false - } - } - - private inner class PacketListenerPublicationSubscriber: Subscriber { - override fun onSubscribe(s: Subscription) { - s.request(Long.MAX_VALUE) - } - - override fun onNext(t: Any?) { - error("Unexpected onNext signal") - } - - override fun onError(t: Throwable?) { - log.atSevere().withCause(t).log("Error in NettyListener method") - } - - override fun onComplete() { - - } - } - - companion object { - private val log = logger() - - private fun resolveDeclaredPacketTypes( - method: Method, - annotation: Handler? - ): ObjectList { - val count = - if (KotlinDetector.isSuspendingFunction(method)) method.parameterCount - 1 else method.parameterCount - - check(count <= 2) { "Maximum of 2 parameters allowed for @${Handler::class.simpleName} method" } - val params = (0 until count).map { ResolvableType.forMethodParameter(method, it) } - val packetType = params.find { it.isAssignableFrom(NettyPacket::class.java) } - val infoType = params.find { it.isAssignableFrom(NettyPacketInfo::class.java) } - - if (annotation != null) { - val classes = annotation.classes - if (classes.isNotEmpty()) { - val invalidParams = - params.filterNot { it.isAssignableFrom(NettyPacketInfo::class.java) } - check(invalidParams.isEmpty()) { "When using @${Handler::class.simpleName}(classes), parameters must be empty or only NettyPacketInfo" } - check(params.count { it.isAssignableFrom(NettyPacketInfo::class.java) } <= 1) { "Only one NettyPacketInfo parameter allowed" } - - return classes.mapTo(mutableObjectListOf(classes.size)) { - ResolvableType.forClass( - it.java - ) - } - } - } - - check(count in 1..2) { "Handler method must have 1 or 2 parameters if no classes are specified in the annotation" } - check(packetType != null) { "Handler method must have a parameter of type NettyPacket" } - - if (params.size == 2) { - check(infoType != null) { "If two parameters are provided, one must be NettyPacket and the other NettyPacketInfo" } - } - - return objectListOf(packetType) - } - - private fun resolveOrder(method: Method): Int { - val annotation = AnnotatedElementUtils.findMergedAnnotation(method, Order::class.java) - return annotation?.value ?: Ordered.LOWEST_PRECEDENCE - } - } -} - - -object NettyListenerRegistry { - fun registerListener(listener: NettyListener<*>) { - - } -} - -class NettyEventExpressionEvaluator(private val originalEvaluationContext: StandardEvaluationContext) : - CachedExpressionEvaluator() { - private val conditionCache = mutableObject2ObjectMapOf(64) - .synchronize() - - fun condition( - conditionExpression: String, - packet: NettyPacket, - targetMethod: Method, - methodKey: AnnotatedElementKey, - args: Array - ): Boolean { - val rootObject = PacketExpressionRootObject(packet, args) - val evaluationContext = createEvaluationContext(rootObject, targetMethod, args) - val expression = getExpression(conditionCache, methodKey, conditionExpression) - val value = expression.getValue(evaluationContext, Boolean::class.java) - - return value == true - } - - private fun createEvaluationContext( - rootObject: PacketExpressionRootObject, - method: Method, - args: Array - ): EvaluationContext { - val evaluationContext = - MethodBasedEvaluationContext(rootObject, method, args, parameterNameDiscoverer) - this.originalEvaluationContext.applyDelegatesTo(evaluationContext) - return evaluationContext - } -} - -@JvmRecord -data class PacketExpressionRootObject( - val packet: NettyPacket, - val args: Array, -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is PacketExpressionRootObject) return false - - if (packet != other.packet) return false - if (!args.contentEquals(other.args)) return false - - return true - } - - override fun hashCode(): Int { - var result = packet.hashCode() - result = 31 * result + args.contentHashCode() - return result - } } \ No newline at end of file