PathHandler.kt

  1. package com.hexagonkt.http.handlers

  2. import com.hexagonkt.core.logging.Logger
  3. import com.hexagonkt.core.media.TEXT_PLAIN
  4. import com.hexagonkt.core.toText
  5. import com.hexagonkt.handlers.ChainHandler
  6. import com.hexagonkt.handlers.Handler
  7. import com.hexagonkt.http.model.*
  8. import com.hexagonkt.http.model.HttpMethod.Companion.ALL
  9. import com.hexagonkt.http.model.HttpStatusType.SERVER_ERROR

  10. data class PathHandler(
  11.     override val handlerPredicate: HttpPredicate,
  12.     val handlers: List<HttpHandler>
  13. ) :
  14.     HttpHandler,
  15.     Handler<HttpCall> by ChainHandler(
  16.         handlers.map { it.addPrefix(handlerPredicate.pathPattern.pattern) },
  17.         handlerPredicate
  18.     )
  19. {

  20.     private companion object {
  21.         val logger: Logger = Logger(PathHandler::class)
  22.         fun nestedMethods(handlers: List<HttpHandler>): Set<HttpMethod> =
  23.             handlers
  24.                 .flatMap { it.handlerPredicate.methods.ifEmpty { ALL } }
  25.                 .toSet()
  26.     }

  27.     constructor(vararg handlers: HttpHandler) :
  28.         this(
  29.             HttpPredicate(methods = nestedMethods(handlers.toList())),
  30.             handlers.toList()
  31.         )

  32.     constructor(pattern: String, handlers: List<HttpHandler>) :
  33.         this(
  34.             HttpPredicate(
  35.                 methods = nestedMethods(handlers.toList()),
  36.                 pattern = pattern,
  37.                 prefix = true,
  38.             ),
  39.             handlers
  40.         )

  41.     constructor(pattern: String, vararg handlers: HttpHandler) :
  42.         this(pattern, handlers.toList())

  43.     override fun process(request: HttpRequestPort): HttpContext =
  44.         process(HttpContext(HttpCall(request = request), predicate)).let {
  45.             val event = it.event
  46.             val response = event.response
  47.             val exception = it.exception

  48.             if (exception != null) {
  49.                 logger.error(exception) {
  50.                     "Exception received at call processing end. Clear/handle exception in a handler"
  51.                 }
  52.                 if (response.status.type != SERVER_ERROR)
  53.                     it.with(
  54.                         event = event.copy(
  55.                             response = response.with(
  56.                                 body = exception.toText(),
  57.                                 contentType = ContentType(TEXT_PLAIN),
  58.                                 status = INTERNAL_SERVER_ERROR_500,
  59.                             )
  60.                         )
  61.                     )
  62.                 else
  63.                     it
  64.             }
  65.             else {
  66.                 it
  67.             }
  68.         } as HttpContext

  69.     override fun addPrefix(prefix: String): HttpHandler =
  70.         copy(handlerPredicate = handlerPredicate.addPrefix(prefix))

  71.     fun describe(): String =
  72.         listOf(
  73.             listOf(handlerPredicate.describe()),
  74.             handlers
  75.                 .map {
  76.                     when (it) {
  77.                         is PathHandler -> it.describe()
  78.                         else -> it.handlerPredicate.describe()
  79.                     }
  80.                 }
  81.                 .map {it.prependIndent(" ".repeat(4)) }
  82.         )
  83.         .flatten()
  84.         .joinToString("\n") { it }
  85. }