commonMain.dk.cachet.carp.common.application.services.EventBus.kt Maven / Gradle / Ivy
Go to download
Helper classes and base types relied upon by all subsystems. This library does not contain any domain logic.
The newest version!
package dk.cachet.carp.common.application.services
import kotlin.reflect.KClass
/**
* A message bus with a publish/subscribe mechanism to distribute integration events across application services.
*/
abstract class EventBus
{
/**
* A [handler] and the associated [eventType] and [eventSource] describing which events it handles.
*/
protected class Handler(
val eventSource: KClass<*>,
val eventType: KClass<*>,
val handler: suspend (IntegrationEvent<*>) -> Unit
)
/**
* Holds the [eventHandlers] of a subscriber and whether the subscriber [isActivated].
*/
protected class SubscriberState
{
val eventHandlers: MutableList = mutableListOf()
var isActivated: Boolean = false
}
private val _subscribers: MutableMap = mutableMapOf()
/**
* All currently registered subscribers, their event handlers, and whether they are activated.
*/
protected val subscribers: Map
get() = _subscribers.toMap()
/**
* Register a [handler] for events of [eventType] emitted by [eventSource] to be received by [subscriber].
*
* @throws IllegalStateException when trying to register a handler for a [subscriber]
* for which [activateHandlers] has already been called.
*/
fun <
TService : ApplicationService,
TEvent : IntegrationEvent
> registerHandler(
eventSource: KClass,
eventType: KClass,
subscriber: Any,
handler: suspend (TEvent) -> Unit
)
{
val subscriberState = _subscribers.getOrPut( subscriber ) { SubscriberState() }
check( !subscriberState.isActivated )
{ "Cannot register event handlers after handlers for subscriber have been activated." }
@Suppress("UNCHECKED_CAST")
val baseHandler = handler as suspend (IntegrationEvent<*>) -> Unit
subscriberState.eventHandlers.add( Handler( eventSource, eventType, baseHandler ) )
}
/**
* Start the event subscription for all registered handlers of [subscriber].
*
* @throws IllegalStateException when this is called more than once.
*/
fun activateHandlers( subscriber: Any )
{
val subscriberState = _subscribers.getOrPut( subscriber ) { SubscriberState() }
check( !subscriberState.isActivated ) { "Can only activate handlers for subscriber once." }
if ( subscriberState.eventHandlers.isNotEmpty() )
{
activateHandlers( subscriber, subscriberState.eventHandlers )
}
subscriberState.isActivated = true
}
/**
* Start the event subscription for [subscriber] using the specified [handlers].
*/
protected abstract fun activateHandlers( subscriber: Any, handlers: List )
/**
* Publish the specified [event] belonging to [publishingService].
*/
abstract suspend fun <
TService : ApplicationService,
TEvent : IntegrationEvent
> publish( publishingService: KClass, event: TEvent )
}
/**
* Publish the specified [event] on this [EventBus].
*/
suspend inline fun <
reified TService : ApplicationService,
reified TEvent : IntegrationEvent
> EventBus.publish( event: TEvent ) = this.publish( TService::class, event )
/**
* Register a [handler] to be received by [subscriber] for events of type [TEvent] on this [EventBus].
*
* @throws IllegalStateException when trying to register a handler for a [subscriber]
* for which `activateHandlers` has already been called.
*/
inline fun <
reified TService : ApplicationService,
reified TEvent : IntegrationEvent
> EventBus.registerHandler( subscriber: Any, noinline handler: suspend (TEvent) -> Unit ) =
this.registerHandler( TService::class, TEvent::class, subscriber, handler )