Skip to content

Commit

Permalink
Organize Sync and Async registration #24
Browse files Browse the repository at this point in the history
  • Loading branch information
osoykan committed Sep 26, 2022
1 parent 1df37ac commit 27204b6
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 147 deletions.
43 changes: 43 additions & 0 deletions kediatr-core/src/main/kotlin/com/trendyol/kediatr/AsyncRegistry.kt
Original file line number Diff line number Diff line change
@@ -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<Class<*>, AsyncCommandProvider<AsyncCommandHandler<Command>>>()
val queryMap = HashMap<Class<*>, AsyncQueryProvider<AsyncQueryHandler<*, *>>>()
val notificationMap =
HashMap<Class<*>, MutableList<AsyncNotificationProvider<AsyncNotificationHandler<*>>>>()
val pipelineSet = HashSet<AsyncPipelineProvider<*>>()
val commandWithResultMap =
HashMap<Class<*>, AsyncCommandWithResultProvider<*>>()

init {

registerFor<AsyncQueryHandler<Query<*>, *>, Query<*>>(dependencyProvider) { key, value ->
queryMap[key] = AsyncQueryProvider(dependencyProvider, value as Class<AsyncQueryHandler<*, *>>)
}

registerFor<AsyncCommandHandler<Command>, Command>(dependencyProvider) { key, value ->
commandMap[key] = AsyncCommandProvider(dependencyProvider, value)
}

registerFor<AsyncCommandWithResultHandler<CommandWithResult<*>, *>, CommandWithResult<*>>(dependencyProvider) { key, value ->
commandWithResultMap[key] = AsyncCommandWithResultProvider(
dependencyProvider,
value as Class<AsyncCommandWithResultHandler<*, *>>
)
}

registerFor<AsyncNotificationHandler<Notification>, Notification>(dependencyProvider) { key, value ->
notificationMap.getOrPut(key) { mutableListOf() }
.add(AsyncNotificationProvider(dependencyProvider, value as Class<AsyncNotificationHandler<*>>))
}

registerFor<AsyncPipelineBehavior>(dependencyProvider) { handler ->
pipelineSet.add(AsyncPipelineProvider(dependencyProvider, handler))
}
}
}
71 changes: 71 additions & 0 deletions kediatr-core/src/main/kotlin/com/trendyol/kediatr/Registrar.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.trendyol.kediatr

import java.lang.reflect.ParameterizedType

@Suppress("UNCHECKED_CAST")
abstract class Registrar {

protected inline fun <reified THandler : Any, TParameter> registerFor(
dependencyProvider: DependencyProvider,
registrar: (key: Class<TParameter>, value: Class<THandler>) -> Unit,
) = dependencyProvider.getSubTypesOf(THandler::class.java).forEach {
registerFor<THandler, TParameter>(it) { key, value ->
registrar(key as Class<TParameter>, value as Class<THandler>)
}
}

protected inline fun <reified THandler : Any, TParameter> registerFor(
handler: Class<*>,
registrar: (key: Class<*>, value: Class<*>) -> Unit,
) {
val interfaceOrBaseClass = THandler::class.java
if (!interfaceOrBaseClass.isAssignableFrom(handler)) return

handler.genericInterfaces
.filterIsInstance<ParameterizedType>()
.map { extractParameter<TParameter>(it) }
.forEach { registrar(it, handler) }

when (handler.genericSuperclass) {
is ParameterizedType -> {
val inheritedHandler = (handler.genericSuperclass as ParameterizedType).rawType as Class<*>
inheritedHandler.genericInterfaces
.filterIsInstance<ParameterizedType>()
.map { extractParameter<TParameter>(handler.genericSuperclass as ParameterizedType) }
.forEach { registrar(it, handler) }
}

is Class<*> -> {
val inheritedHandler = (handler.genericSuperclass as Class<*>)
if (interfaceOrBaseClass.isAssignableFrom(inheritedHandler)) {
inheritedHandler.genericInterfaces
.filterIsInstance<ParameterizedType>()
.map { extractParameter<TParameter>(it) }
.forEach { registrar(it, handler) }
}
}
}
}

protected inline fun <reified T> registerFor(
dependencyProvider: DependencyProvider,
registrar: (value: Class<T>) -> Unit,
) = dependencyProvider.getSubTypesOf(T::class.java).forEach { handler ->
registerFor<T>(handler) { value -> registrar(value as Class<T>) }
}

protected inline fun <reified T> registerFor(
handler: Class<*>,
registrar: (value: Class<*>) -> Unit,
) {
val interfaceOrBaseClass = T::class.java
if (!interfaceOrBaseClass.isAssignableFrom(handler)) return
registrar(handler)
}

protected fun <T> extractParameter(genericInterface: ParameterizedType): Class<out T> =
when (val typeArgument = genericInterface.actualTypeArguments[0]) {
is ParameterizedType -> typeArgument.rawType as Class<out T>
else -> typeArgument as Class<out T>
}
}
184 changes: 37 additions & 147 deletions kediatr-core/src/main/kotlin/com/trendyol/kediatr/RegistryImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<Class<*>, QueryProvider<QueryHandler<*, *>>>()
private val commandMap = HashMap<Class<*>, CommandProvider<CommandHandler<Command>>>()
private val notificationMap = HashMap<Class<*>, MutableList<NotificationProvider<NotificationHandler<*>>>>()
private val pipelineSet = HashSet<PipelineProvider<*>>()
private val commandWithResultMap = HashMap<Class<*>, CommandWithResultProvider<CommandWithResultHandler<*, *>>>()

private val asyncCommandMap = HashMap<Class<*>, AsyncCommandProvider<AsyncCommandHandler<Command>>>()
private val asyncQueryMap = HashMap<Class<*>, AsyncQueryProvider<AsyncQueryHandler<*, *>>>()
private val asyncNotificationMap =
HashMap<Class<*>, MutableList<AsyncNotificationProvider<AsyncNotificationHandler<*>>>>()
private val asyncPipelineSet = HashSet<AsyncPipelineProvider<*>>()
private val asyncCommandWithResultMap =
HashMap<Class<*>, AsyncCommandWithResultProvider<*>>()

init {

registerFor<QueryHandler<Query<*>, *>, Query<*>>(dependencyProvider) { key, value ->
queryMap[key] = QueryProvider(dependencyProvider, value as Class<QueryHandler<*, *>>)
}

registerFor<CommandHandler<Command>, Command>(dependencyProvider) { key, value ->
commandMap[key] = CommandProvider(dependencyProvider, value)
}

registerFor<CommandWithResultHandler<CommandWithResult<*>, *>, CommandWithResult<*>>(dependencyProvider) { key, value ->
commandWithResultMap[key] =
CommandWithResultProvider(dependencyProvider, value as Class<CommandWithResultHandler<*, *>>)
}

registerFor<NotificationHandler<Notification>, Notification>(dependencyProvider) { key, value ->
notificationMap.getOrPut(key) { mutableListOf() }
.add(NotificationProvider(dependencyProvider, value as Class<NotificationHandler<*>>))
}

registerFor<AsyncQueryHandler<Query<*>, *>, Query<*>>(dependencyProvider) { key, value ->
asyncQueryMap[key] = AsyncQueryProvider(dependencyProvider, value as Class<AsyncQueryHandler<*, *>>)
}

registerFor<AsyncCommandHandler<Command>, Command>(dependencyProvider) { key, value ->
asyncCommandMap[key] = AsyncCommandProvider(dependencyProvider, value)
}

registerFor<AsyncCommandWithResultHandler<CommandWithResult<*>, *>, CommandWithResult<*>>(dependencyProvider) { key, value ->
asyncCommandWithResultMap[key] = AsyncCommandWithResultProvider(
dependencyProvider,
value as Class<AsyncCommandWithResultHandler<*, *>>
)
}

registerFor<AsyncNotificationHandler<Notification>, Notification>(dependencyProvider) { key, value ->
asyncNotificationMap.getOrPut(key) { mutableListOf() }
.add(AsyncNotificationProvider(dependencyProvider, value as Class<AsyncNotificationHandler<*>>))
}

registerFor<AsyncPipelineBehavior>(dependencyProvider) { handler ->
asyncPipelineSet.add(AsyncPipelineProvider(dependencyProvider, handler))
}

registerFor<PipelineBehavior>(dependencyProvider) { handler ->
pipelineSet.add(PipelineProvider(dependencyProvider, handler))
}
}

private inline fun <reified T> registerFor(
dependencyProvider: DependencyProvider,
registrar: (value: Class<T>) -> Unit
) = dependencyProvider.getSubTypesOf(T::class.java).forEach { handler ->
registerFor<T>(handler) { value -> registrar(value as Class<T>) }
}

private inline fun <reified T> registerFor(
handler: Class<*>,
registrar: (value: Class<*>) -> Unit
) {
val interfaceOrBaseClass = T::class.java
if (!interfaceOrBaseClass.isAssignableFrom(handler)) return
registrar(handler)
}

private inline fun <reified THandler : Any, TParameter> registerFor(
dependencyProvider: DependencyProvider,
registrar: (key: Class<TParameter>, value: Class<THandler>) -> Unit
) = dependencyProvider.getSubTypesOf(THandler::class.java).forEach {
registerFor<THandler, TParameter>(it) { key, value ->
registrar(key as Class<TParameter>, value as Class<THandler>)
}
}

private inline fun <reified THandler : Any, TParameter> registerFor(
handler: Class<*>,
registrar: (key: Class<*>, value: Class<*>) -> Unit
) {
val interfaceOrBaseClass = THandler::class.java
if (!interfaceOrBaseClass.isAssignableFrom(handler)) return

handler.genericInterfaces
.filterIsInstance<ParameterizedType>()
.map { extractParameter<TParameter>(it) }
.forEach { registrar(it, handler) }

when (handler.genericSuperclass) {
is ParameterizedType -> {
val inheritedHandler = (handler.genericSuperclass as ParameterizedType).rawType as Class<*>
inheritedHandler.genericInterfaces
.filterIsInstance<ParameterizedType>()
.map { extractParameter<TParameter>(handler.genericSuperclass as ParameterizedType) }
.forEach { registrar(it, handler) }
}

is Class<*> -> {
val inheritedHandler = (handler.genericSuperclass as Class<*>)
if (interfaceOrBaseClass.isAssignableFrom(inheritedHandler)) {
inheritedHandler.genericInterfaces
.filterIsInstance<ParameterizedType>()
.map { extractParameter<TParameter>(it) }
.forEach { registrar(it, handler) }
}
}
}
}

private fun <T> extractParameter(genericInterface: ParameterizedType): Class<out T> =
when (val typeArgument = genericInterface.actualTypeArguments[0]) {
is ParameterizedType -> typeArgument.rawType as Class<out T>
else -> typeArgument as Class<out T>
}
private val syncRegistry = SyncRegistry(dependencyProvider)
private val asyncRegistry = AsyncRegistry(dependencyProvider)

override fun <TCommand : Command> resolveCommandHandler(classOfCommand: Class<TCommand>): CommandHandler<TCommand> {
val handler = commandMap[classOfCommand]?.get()
override fun <TCommand : Command> resolveCommandHandler(
classOfCommand: Class<TCommand>,
): CommandHandler<TCommand> {
val handler = syncRegistry.commandMap[classOfCommand]?.get()
?: throw HandlerNotFoundException("handler could not be found for ${classOfCommand.name}")
return handler as CommandHandler<TCommand>
}

override fun <TCommand : CommandWithResult<TResult>, TResult> resolveCommandWithResultHandler(classOfCommand: Class<TCommand>): CommandWithResultHandler<TCommand, TResult> {
val handler = commandWithResultMap[classOfCommand]?.get()
override fun <TCommand : CommandWithResult<TResult>, TResult> resolveCommandWithResultHandler(
classOfCommand: Class<TCommand>,
): CommandWithResultHandler<TCommand, TResult> {
val handler = syncRegistry.commandWithResultMap[classOfCommand]?.get()
?: throw HandlerNotFoundException("handler could not be found for ${classOfCommand.name}")
return handler as CommandWithResultHandler<TCommand, TResult>
}

override fun <TNotification : Notification> resolveNotificationHandlers(classOfNotification: Class<TNotification>): Collection<NotificationHandler<TNotification>> =
notificationMap.filter { (k, _) -> k.isAssignableFrom(classOfNotification) }
override fun <TNotification : Notification> resolveNotificationHandlers(
classOfNotification: Class<TNotification>,
): Collection<NotificationHandler<TNotification>> =
syncRegistry.notificationMap.filter { (k, _) -> k.isAssignableFrom(classOfNotification) }
.flatMap { (_, v) -> v.map { it.get() as NotificationHandler<TNotification> } }

override fun <TQuery : Query<TResult>, TResult> resolveQueryHandler(classOfQuery: Class<TQuery>): QueryHandler<TQuery, TResult> {
val handler = queryMap[classOfQuery]?.get()
override fun <TQuery : Query<TResult>, TResult> resolveQueryHandler(
classOfQuery: Class<TQuery>,
): QueryHandler<TQuery, TResult> {
val handler = syncRegistry.queryMap[classOfQuery]?.get()
?: throw HandlerNotFoundException("handler could not be found for ${classOfQuery.name}")
return handler as QueryHandler<TQuery, TResult>
}

override fun <TCommand : Command> resolveAsyncCommandHandler(classOfCommand: Class<TCommand>): AsyncCommandHandler<TCommand> {
val handler = asyncCommandMap[classOfCommand]?.get()
override fun <TCommand : Command> resolveAsyncCommandHandler(
classOfCommand: Class<TCommand>,
): AsyncCommandHandler<TCommand> {
val handler = asyncRegistry.commandMap[classOfCommand]?.get()
?: throw HandlerNotFoundException("handler could not be found for ${classOfCommand.name}")
return handler as AsyncCommandHandler<TCommand>
}

override fun <TCommand : CommandWithResult<TResult>, TResult> resolveAsyncCommandWithResultHandler(classOfCommand: Class<TCommand>): AsyncCommandWithResultHandler<TCommand, TResult> {
val handler = asyncCommandWithResultMap[classOfCommand]?.get()
override fun <TCommand : CommandWithResult<TResult>, TResult> resolveAsyncCommandWithResultHandler(
classOfCommand: Class<TCommand>,
): AsyncCommandWithResultHandler<TCommand, TResult> {
val handler = asyncRegistry.commandWithResultMap[classOfCommand]?.get()
?: throw HandlerNotFoundException("handler could not be found for ${classOfCommand.name}")
return handler as AsyncCommandWithResultHandler<TCommand, TResult>
}

override fun <TNotification : Notification> resolveAsyncNotificationHandlers(classOfNotification: Class<TNotification>): Collection<AsyncNotificationHandler<TNotification>> =
asyncNotificationMap.filter { (k, _) -> k.isAssignableFrom(classOfNotification) }
override fun <TNotification : Notification> resolveAsyncNotificationHandlers(
classOfNotification: Class<TNotification>,
): Collection<AsyncNotificationHandler<TNotification>> =
asyncRegistry.notificationMap.filter { (k, _) -> k.isAssignableFrom(classOfNotification) }
.flatMap { (_, v) -> v.map { it.get() as AsyncNotificationHandler<TNotification> } }

override fun <TQuery : Query<TResult>, TResult> resolveAsyncQueryHandler(classOfQuery: Class<TQuery>): AsyncQueryHandler<TQuery, TResult> {
val handler = asyncQueryMap[classOfQuery]?.get()
override fun <TQuery : Query<TResult>, TResult> resolveAsyncQueryHandler(
classOfQuery: Class<TQuery>,
): AsyncQueryHandler<TQuery, TResult> {
val handler = asyncRegistry.queryMap[classOfQuery]?.get()
?: throw HandlerNotFoundException("handler could not be found for ${classOfQuery.name}")
return handler as AsyncQueryHandler<TQuery, TResult>
}

override fun getPipelineBehaviors(): Collection<PipelineBehavior> = pipelineSet.map { it.get() }
override fun getPipelineBehaviors(): Collection<PipelineBehavior> = syncRegistry.pipelineSet.map { it.get() }

override fun getAsyncPipelineBehaviors(): Collection<AsyncPipelineBehavior> = asyncPipelineSet.map { it.get() }
override fun getAsyncPipelineBehaviors(): Collection<AsyncPipelineBehavior> = asyncRegistry.pipelineSet.map { it.get() }
}
38 changes: 38 additions & 0 deletions kediatr-core/src/main/kotlin/com/trendyol/kediatr/SyncRegistry.kt
Original file line number Diff line number Diff line change
@@ -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<Class<*>, QueryProvider<QueryHandler<*, *>>>()
val commandMap = HashMap<Class<*>, CommandProvider<CommandHandler<Command>>>()
val notificationMap = HashMap<Class<*>, MutableList<NotificationProvider<NotificationHandler<*>>>>()
val pipelineSet = HashSet<PipelineProvider<*>>()
val commandWithResultMap = HashMap<Class<*>, CommandWithResultProvider<CommandWithResultHandler<*, *>>>()

init {
registerFor<QueryHandler<Query<*>, *>, Query<*>>(dependencyProvider) { key, value ->
queryMap[key] = QueryProvider(dependencyProvider, value as Class<QueryHandler<*, *>>)
}

registerFor<CommandHandler<Command>, Command>(dependencyProvider) { key, value ->
commandMap[key] = CommandProvider(dependencyProvider, value)
}

registerFor<CommandWithResultHandler<CommandWithResult<*>, *>, CommandWithResult<*>>(dependencyProvider) { key, value ->
commandWithResultMap[key] =
CommandWithResultProvider(dependencyProvider, value as Class<CommandWithResultHandler<*, *>>)
}

registerFor<NotificationHandler<Notification>, Notification>(dependencyProvider) { key, value ->
notificationMap.getOrPut(key) { mutableListOf() }
.add(NotificationProvider(dependencyProvider, value as Class<NotificationHandler<*>>))
}

registerFor<PipelineBehavior>(dependencyProvider) { handler ->
pipelineSet.add(PipelineProvider(dependencyProvider, handler))
}
}
}

0 comments on commit 27204b6

Please sign in to comment.