From 27204b603aa1a7291b4cb5cc5915456a300c5401 Mon Sep 17 00:00:00 2001 From: Oguzhan Soykan Date: Sat, 24 Sep 2022 16:09:08 +0200 Subject: [PATCH] Organize Sync and Async registration #24 --- .../com/trendyol/kediatr/AsyncRegistry.kt | 43 ++++ .../kotlin/com/trendyol/kediatr/Registrar.kt | 71 +++++++ .../com/trendyol/kediatr/RegistryImpl.kt | 184 ++++-------------- .../com/trendyol/kediatr/SyncRegistry.kt | 38 ++++ 4 files changed, 189 insertions(+), 147 deletions(-) create mode 100644 kediatr-core/src/main/kotlin/com/trendyol/kediatr/AsyncRegistry.kt create mode 100644 kediatr-core/src/main/kotlin/com/trendyol/kediatr/Registrar.kt create mode 100644 kediatr-core/src/main/kotlin/com/trendyol/kediatr/SyncRegistry.kt diff --git a/kediatr-core/src/main/kotlin/com/trendyol/kediatr/AsyncRegistry.kt b/kediatr-core/src/main/kotlin/com/trendyol/kediatr/AsyncRegistry.kt new file mode 100644 index 0000000..25e20a5 --- /dev/null +++ b/kediatr-core/src/main/kotlin/com/trendyol/kediatr/AsyncRegistry.kt @@ -0,0 +1,43 @@ +package com.trendyol.kediatr + +import com.trendyol.kediatr.common.AsyncNotificationProvider +import com.trendyol.kediatr.common.AsyncPipelineProvider +import com.trendyol.kediatr.common.AsyncQueryProvider + +@Suppress("UNCHECKED_CAST") +internal class AsyncRegistry(dependencyProvider: DependencyProvider) : Registrar() { + val commandMap = HashMap, AsyncCommandProvider>>() + val queryMap = HashMap, AsyncQueryProvider>>() + val notificationMap = + HashMap, MutableList>>>() + val pipelineSet = HashSet>() + val commandWithResultMap = + HashMap, AsyncCommandWithResultProvider<*>>() + + init { + + registerFor, *>, Query<*>>(dependencyProvider) { key, value -> + queryMap[key] = AsyncQueryProvider(dependencyProvider, value as Class>) + } + + registerFor, Command>(dependencyProvider) { key, value -> + commandMap[key] = AsyncCommandProvider(dependencyProvider, value) + } + + registerFor, *>, CommandWithResult<*>>(dependencyProvider) { key, value -> + commandWithResultMap[key] = AsyncCommandWithResultProvider( + dependencyProvider, + value as Class> + ) + } + + registerFor, Notification>(dependencyProvider) { key, value -> + notificationMap.getOrPut(key) { mutableListOf() } + .add(AsyncNotificationProvider(dependencyProvider, value as Class>)) + } + + registerFor(dependencyProvider) { handler -> + pipelineSet.add(AsyncPipelineProvider(dependencyProvider, handler)) + } + } +} diff --git a/kediatr-core/src/main/kotlin/com/trendyol/kediatr/Registrar.kt b/kediatr-core/src/main/kotlin/com/trendyol/kediatr/Registrar.kt new file mode 100644 index 0000000..c883bd0 --- /dev/null +++ b/kediatr-core/src/main/kotlin/com/trendyol/kediatr/Registrar.kt @@ -0,0 +1,71 @@ +package com.trendyol.kediatr + +import java.lang.reflect.ParameterizedType + +@Suppress("UNCHECKED_CAST") +abstract class Registrar { + + protected inline fun registerFor( + dependencyProvider: DependencyProvider, + registrar: (key: Class, value: Class) -> Unit, + ) = dependencyProvider.getSubTypesOf(THandler::class.java).forEach { + registerFor(it) { key, value -> + registrar(key as Class, value as Class) + } + } + + protected inline fun registerFor( + handler: Class<*>, + registrar: (key: Class<*>, value: Class<*>) -> Unit, + ) { + val interfaceOrBaseClass = THandler::class.java + if (!interfaceOrBaseClass.isAssignableFrom(handler)) return + + handler.genericInterfaces + .filterIsInstance() + .map { extractParameter(it) } + .forEach { registrar(it, handler) } + + when (handler.genericSuperclass) { + is ParameterizedType -> { + val inheritedHandler = (handler.genericSuperclass as ParameterizedType).rawType as Class<*> + inheritedHandler.genericInterfaces + .filterIsInstance() + .map { extractParameter(handler.genericSuperclass as ParameterizedType) } + .forEach { registrar(it, handler) } + } + + is Class<*> -> { + val inheritedHandler = (handler.genericSuperclass as Class<*>) + if (interfaceOrBaseClass.isAssignableFrom(inheritedHandler)) { + inheritedHandler.genericInterfaces + .filterIsInstance() + .map { extractParameter(it) } + .forEach { registrar(it, handler) } + } + } + } + } + + protected inline fun registerFor( + dependencyProvider: DependencyProvider, + registrar: (value: Class) -> Unit, + ) = dependencyProvider.getSubTypesOf(T::class.java).forEach { handler -> + registerFor(handler) { value -> registrar(value as Class) } + } + + protected inline fun registerFor( + handler: Class<*>, + registrar: (value: Class<*>) -> Unit, + ) { + val interfaceOrBaseClass = T::class.java + if (!interfaceOrBaseClass.isAssignableFrom(handler)) return + registrar(handler) + } + + protected fun extractParameter(genericInterface: ParameterizedType): Class = + when (val typeArgument = genericInterface.actualTypeArguments[0]) { + is ParameterizedType -> typeArgument.rawType as Class + else -> typeArgument as Class + } +} diff --git a/kediatr-core/src/main/kotlin/com/trendyol/kediatr/RegistryImpl.kt b/kediatr-core/src/main/kotlin/com/trendyol/kediatr/RegistryImpl.kt index 34f2135..32d5258 100644 --- a/kediatr-core/src/main/kotlin/com/trendyol/kediatr/RegistryImpl.kt +++ b/kediatr-core/src/main/kotlin/com/trendyol/kediatr/RegistryImpl.kt @@ -2,184 +2,74 @@ package com.trendyol.kediatr -import com.trendyol.kediatr.common.* -import java.lang.reflect.ParameterizedType - class RegistryImpl( - dependencyProvider: DependencyProvider + dependencyProvider: DependencyProvider, ) : Registry { - private val queryMap = HashMap, QueryProvider>>() - private val commandMap = HashMap, CommandProvider>>() - private val notificationMap = HashMap, MutableList>>>() - private val pipelineSet = HashSet>() - private val commandWithResultMap = HashMap, CommandWithResultProvider>>() - - private val asyncCommandMap = HashMap, AsyncCommandProvider>>() - private val asyncQueryMap = HashMap, AsyncQueryProvider>>() - private val asyncNotificationMap = - HashMap, MutableList>>>() - private val asyncPipelineSet = HashSet>() - private val asyncCommandWithResultMap = - HashMap, AsyncCommandWithResultProvider<*>>() - - init { - - registerFor, *>, Query<*>>(dependencyProvider) { key, value -> - queryMap[key] = QueryProvider(dependencyProvider, value as Class>) - } - - registerFor, Command>(dependencyProvider) { key, value -> - commandMap[key] = CommandProvider(dependencyProvider, value) - } - - registerFor, *>, CommandWithResult<*>>(dependencyProvider) { key, value -> - commandWithResultMap[key] = - CommandWithResultProvider(dependencyProvider, value as Class>) - } - - registerFor, Notification>(dependencyProvider) { key, value -> - notificationMap.getOrPut(key) { mutableListOf() } - .add(NotificationProvider(dependencyProvider, value as Class>)) - } - - registerFor, *>, Query<*>>(dependencyProvider) { key, value -> - asyncQueryMap[key] = AsyncQueryProvider(dependencyProvider, value as Class>) - } - - registerFor, Command>(dependencyProvider) { key, value -> - asyncCommandMap[key] = AsyncCommandProvider(dependencyProvider, value) - } - - registerFor, *>, CommandWithResult<*>>(dependencyProvider) { key, value -> - asyncCommandWithResultMap[key] = AsyncCommandWithResultProvider( - dependencyProvider, - value as Class> - ) - } - - registerFor, Notification>(dependencyProvider) { key, value -> - asyncNotificationMap.getOrPut(key) { mutableListOf() } - .add(AsyncNotificationProvider(dependencyProvider, value as Class>)) - } - - registerFor(dependencyProvider) { handler -> - asyncPipelineSet.add(AsyncPipelineProvider(dependencyProvider, handler)) - } - - registerFor(dependencyProvider) { handler -> - pipelineSet.add(PipelineProvider(dependencyProvider, handler)) - } - } - - private inline fun registerFor( - dependencyProvider: DependencyProvider, - registrar: (value: Class) -> Unit - ) = dependencyProvider.getSubTypesOf(T::class.java).forEach { handler -> - registerFor(handler) { value -> registrar(value as Class) } - } - - private inline fun registerFor( - handler: Class<*>, - registrar: (value: Class<*>) -> Unit - ) { - val interfaceOrBaseClass = T::class.java - if (!interfaceOrBaseClass.isAssignableFrom(handler)) return - registrar(handler) - } - - private inline fun registerFor( - dependencyProvider: DependencyProvider, - registrar: (key: Class, value: Class) -> Unit - ) = dependencyProvider.getSubTypesOf(THandler::class.java).forEach { - registerFor(it) { key, value -> - registrar(key as Class, value as Class) - } - } - - private inline fun registerFor( - handler: Class<*>, - registrar: (key: Class<*>, value: Class<*>) -> Unit - ) { - val interfaceOrBaseClass = THandler::class.java - if (!interfaceOrBaseClass.isAssignableFrom(handler)) return - - handler.genericInterfaces - .filterIsInstance() - .map { extractParameter(it) } - .forEach { registrar(it, handler) } - - when (handler.genericSuperclass) { - is ParameterizedType -> { - val inheritedHandler = (handler.genericSuperclass as ParameterizedType).rawType as Class<*> - inheritedHandler.genericInterfaces - .filterIsInstance() - .map { extractParameter(handler.genericSuperclass as ParameterizedType) } - .forEach { registrar(it, handler) } - } - - is Class<*> -> { - val inheritedHandler = (handler.genericSuperclass as Class<*>) - if (interfaceOrBaseClass.isAssignableFrom(inheritedHandler)) { - inheritedHandler.genericInterfaces - .filterIsInstance() - .map { extractParameter(it) } - .forEach { registrar(it, handler) } - } - } - } - } - private fun extractParameter(genericInterface: ParameterizedType): Class = - when (val typeArgument = genericInterface.actualTypeArguments[0]) { - is ParameterizedType -> typeArgument.rawType as Class - else -> typeArgument as Class - } + private val syncRegistry = SyncRegistry(dependencyProvider) + private val asyncRegistry = AsyncRegistry(dependencyProvider) - override fun resolveCommandHandler(classOfCommand: Class): CommandHandler { - val handler = commandMap[classOfCommand]?.get() + override fun resolveCommandHandler( + classOfCommand: Class, + ): CommandHandler { + val handler = syncRegistry.commandMap[classOfCommand]?.get() ?: throw HandlerNotFoundException("handler could not be found for ${classOfCommand.name}") return handler as CommandHandler } - override fun , TResult> resolveCommandWithResultHandler(classOfCommand: Class): CommandWithResultHandler { - val handler = commandWithResultMap[classOfCommand]?.get() + override fun , TResult> resolveCommandWithResultHandler( + classOfCommand: Class, + ): CommandWithResultHandler { + val handler = syncRegistry.commandWithResultMap[classOfCommand]?.get() ?: throw HandlerNotFoundException("handler could not be found for ${classOfCommand.name}") return handler as CommandWithResultHandler } - override fun resolveNotificationHandlers(classOfNotification: Class): Collection> = - notificationMap.filter { (k, _) -> k.isAssignableFrom(classOfNotification) } + override fun resolveNotificationHandlers( + classOfNotification: Class, + ): Collection> = + syncRegistry.notificationMap.filter { (k, _) -> k.isAssignableFrom(classOfNotification) } .flatMap { (_, v) -> v.map { it.get() as NotificationHandler } } - override fun , TResult> resolveQueryHandler(classOfQuery: Class): QueryHandler { - val handler = queryMap[classOfQuery]?.get() + override fun , TResult> resolveQueryHandler( + classOfQuery: Class, + ): QueryHandler { + val handler = syncRegistry.queryMap[classOfQuery]?.get() ?: throw HandlerNotFoundException("handler could not be found for ${classOfQuery.name}") return handler as QueryHandler } - override fun resolveAsyncCommandHandler(classOfCommand: Class): AsyncCommandHandler { - val handler = asyncCommandMap[classOfCommand]?.get() + override fun resolveAsyncCommandHandler( + classOfCommand: Class, + ): AsyncCommandHandler { + val handler = asyncRegistry.commandMap[classOfCommand]?.get() ?: throw HandlerNotFoundException("handler could not be found for ${classOfCommand.name}") return handler as AsyncCommandHandler } - override fun , TResult> resolveAsyncCommandWithResultHandler(classOfCommand: Class): AsyncCommandWithResultHandler { - val handler = asyncCommandWithResultMap[classOfCommand]?.get() + override fun , TResult> resolveAsyncCommandWithResultHandler( + classOfCommand: Class, + ): AsyncCommandWithResultHandler { + val handler = asyncRegistry.commandWithResultMap[classOfCommand]?.get() ?: throw HandlerNotFoundException("handler could not be found for ${classOfCommand.name}") return handler as AsyncCommandWithResultHandler } - override fun resolveAsyncNotificationHandlers(classOfNotification: Class): Collection> = - asyncNotificationMap.filter { (k, _) -> k.isAssignableFrom(classOfNotification) } + override fun resolveAsyncNotificationHandlers( + classOfNotification: Class, + ): Collection> = + asyncRegistry.notificationMap.filter { (k, _) -> k.isAssignableFrom(classOfNotification) } .flatMap { (_, v) -> v.map { it.get() as AsyncNotificationHandler } } - override fun , TResult> resolveAsyncQueryHandler(classOfQuery: Class): AsyncQueryHandler { - val handler = asyncQueryMap[classOfQuery]?.get() + override fun , TResult> resolveAsyncQueryHandler( + classOfQuery: Class, + ): AsyncQueryHandler { + val handler = asyncRegistry.queryMap[classOfQuery]?.get() ?: throw HandlerNotFoundException("handler could not be found for ${classOfQuery.name}") return handler as AsyncQueryHandler } - override fun getPipelineBehaviors(): Collection = pipelineSet.map { it.get() } + override fun getPipelineBehaviors(): Collection = syncRegistry.pipelineSet.map { it.get() } - override fun getAsyncPipelineBehaviors(): Collection = asyncPipelineSet.map { it.get() } + override fun getAsyncPipelineBehaviors(): Collection = asyncRegistry.pipelineSet.map { it.get() } } diff --git a/kediatr-core/src/main/kotlin/com/trendyol/kediatr/SyncRegistry.kt b/kediatr-core/src/main/kotlin/com/trendyol/kediatr/SyncRegistry.kt new file mode 100644 index 0000000..5e77434 --- /dev/null +++ b/kediatr-core/src/main/kotlin/com/trendyol/kediatr/SyncRegistry.kt @@ -0,0 +1,38 @@ +package com.trendyol.kediatr + +import com.trendyol.kediatr.common.NotificationProvider +import com.trendyol.kediatr.common.PipelineProvider +import com.trendyol.kediatr.common.QueryProvider + +@Suppress("UNCHECKED_CAST") +internal class SyncRegistry(dependencyProvider: DependencyProvider) : Registrar() { + val queryMap = HashMap, QueryProvider>>() + val commandMap = HashMap, CommandProvider>>() + val notificationMap = HashMap, MutableList>>>() + val pipelineSet = HashSet>() + val commandWithResultMap = HashMap, CommandWithResultProvider>>() + + init { + registerFor, *>, Query<*>>(dependencyProvider) { key, value -> + queryMap[key] = QueryProvider(dependencyProvider, value as Class>) + } + + registerFor, Command>(dependencyProvider) { key, value -> + commandMap[key] = CommandProvider(dependencyProvider, value) + } + + registerFor, *>, CommandWithResult<*>>(dependencyProvider) { key, value -> + commandWithResultMap[key] = + CommandWithResultProvider(dependencyProvider, value as Class>) + } + + registerFor, Notification>(dependencyProvider) { key, value -> + notificationMap.getOrPut(key) { mutableListOf() } + .add(NotificationProvider(dependencyProvider, value as Class>)) + } + + registerFor(dependencyProvider) { handler -> + pipelineSet.add(PipelineProvider(dependencyProvider, handler)) + } + } +}