ExceptionHandler.kt

  1. package com.hexagontk.handlers

  2. import kotlin.reflect.KClass
  3. import kotlin.reflect.cast

  4. /**
  5.  * After handlers are executed even if a filter don't call next handler (if after was added before
  6.  * filter).
  7.  *
  8.  * After handlers' filters are always true because they are meant to be evaluated on the **return**.
  9.  * If they are not called in first place, they won't be executed on the return of the next handler.
  10.  * Their filter is evaluated after the `next` call, not before.
  11.  */
  12. class ExceptionHandler<T : Any, E : Exception>(
  13.     val exception: KClass<E>,
  14.     val exceptionCallback: (Context<T>, E) -> Context<T>,
  15. ) : Handler<T> {

  16.     internal companion object {
  17.         fun <T : Exception> castException(exception: Exception?, exceptionClass: KClass<T>): T =
  18.             exception
  19.                 ?.let { exceptionClass.cast(exception) }
  20.                 ?: error("Exception 'null' or incorrect type")
  21.     }

  22.     override val predicate: (Context<T>) -> Boolean = { true }
  23.     val callback: (Context<T>) -> Context<T> = { context ->
  24.         exceptionCallback(context, castException(context.exception, exception))
  25.             .with(exception = null)
  26.     }

  27.     override fun process(context: Context<T>): Context<T> {
  28.         val next = context.next().with(predicate = ::afterPredicate)
  29.         return try {
  30.             if (afterPredicate(next)) callback(next)
  31.             else next
  32.         }
  33.         catch (e: Exception) {
  34.             next.with(exception = e)
  35.         }
  36.     }

  37.     private fun afterPredicate(context: Context<T>): Boolean {
  38.         val exceptionClass = context.exception?.javaClass ?: return false
  39.         return exception.java.isAssignableFrom(exceptionClass)
  40.     }
  41. }