ServletServer.kt

  1. package com.hexagontk.http.server.servlet

  2. import com.hexagontk.core.text.AnsiColor.BLUE
  3. import com.hexagontk.core.text.AnsiEffect.BOLD
  4. import com.hexagontk.core.text.AnsiColor.CYAN
  5. import com.hexagontk.core.text.AnsiColor.MAGENTA
  6. import com.hexagontk.core.text.Ansi.RESET
  7. import com.hexagontk.core.Platform
  8. import com.hexagontk.core.Platform.cpuCount
  9. import com.hexagontk.core.Platform.hostName
  10. import com.hexagontk.core.Platform.localeCode
  11. import com.hexagontk.core.Platform.name
  12. import com.hexagontk.core.Platform.timeZone
  13. import com.hexagontk.core.Platform.totalMemory
  14. import com.hexagontk.core.Platform.usedMemory
  15. import com.hexagontk.core.Platform.version
  16. import com.hexagontk.core.Process
  17. import com.hexagontk.core.text.prependIndent
  18. import com.hexagontk.core.require
  19. import com.hexagontk.http.server.HttpServer
  20. import com.hexagontk.http.server.serverBanner
  21. import com.hexagontk.http.handlers.HttpHandler
  22. import com.hexagontk.http.handlers.OnHandler
  23. import jakarta.servlet.*
  24. import java.util.*

  25. /**
  26.  * Adapter to run a router inside a Servlets container. It is not a standard engine as it is not
  27.  * started/stopped (not passed to an [HttpServer]).
  28.  */
  29. abstract class ServletServer(
  30.     private val handler: HttpHandler = OnHandler { this },
  31. ) : ServletContextListener {

  32.     override fun contextInitialized(sce: ServletContextEvent) {
  33.         val servletFilter = ServletFilter(handler)
  34.         // Let's be a good JEE citizen
  35.         val servletContext = sce.servletContext
  36.         servletFilter.init(object : FilterConfig {
  37.             val params = Hashtable<String, String>(1).apply { put("filterName", filterName) }
  38.             override fun getFilterName(): String = ServletFilter::class.java.name
  39.             override fun getServletContext(): ServletContext = servletContext
  40.             override fun getInitParameter(name: String): String = params.require(name)
  41.             override fun getInitParameterNames(): Enumeration<String> = params.keys()
  42.         })
  43.         val filter = servletContext.addFilter("filters", servletFilter)
  44.         filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType::class.java), true, "/*")
  45.     }

  46.     fun createBanner(
  47.         startUpTimestamp: Long = -1, banner: String = serverBanner, detailed: Boolean = false
  48.     ): String {
  49.         val server = "$BOLD$CYAN${javaClass.simpleName}$RESET"
  50.         val java = "$BOLD${BLUE}Java $version$RESET [$BLUE$name$RESET]"
  51.         val locale = "$BLUE$localeCode$RESET"
  52.         val timezone = "$BLUE${timeZone.id}$RESET"
  53.         val charsetValue = "$BLUE${Platform.charset}$RESET"
  54.         val start = if (startUpTimestamp < 0) "<undefined>" else startUpTimestamp.toString()
  55.         val startTime = "$BOLD$MAGENTA in $start ms$RESET"

  56.         val information = if (detailed)
  57.             detailBanner(server, java, locale, timezone, charsetValue, startTime)
  58.         else
  59.             """

  60.             Server Adapter: $server

  61.             🛠 Using $java
  62.             🌍 Locale: $locale Timezone: $timezone Charset: $charsetValue

  63.             ⏱️ Started$startTime
  64.             🚀 Served at a JEE Server

  65.             """

  66.         val fullBanner = banner + information.trimIndent()
  67.         return "\n" + fullBanner.prependIndent()
  68.     }

  69.     private fun detailBanner(
  70.         server: String,
  71.         java: String,
  72.         locale: String,
  73.         timezone: String,
  74.         charsetValue: String,
  75.         startTime: String
  76.     ): String {
  77.         val bootTime = "%01.3f".format(Process.uptime() / 1e3)
  78.         val uptimeValue = "$BOLD$MAGENTA$bootTime s$RESET"
  79.         val jvmMemoryValue = "$BLUE${totalMemory()} KB$RESET"
  80.         val usedMemoryValue = "$BOLD$MAGENTA${usedMemory()} KB$RESET"
  81.         val hostnameValue = "$BLUE$hostName$RESET"
  82.         val cpuCountValue = "$BLUE$cpuCount$RESET"

  83.         return """

  84.             Server Adapter: $server

  85.             🖥️️ Running in '$hostnameValue' with $cpuCountValue CPUs $jvmMemoryValue of memory
  86.             🛠 Using $java
  87.             🌍 Locale: $locale Timezone: $timezone Charset: $charsetValue

  88.             ⏱️ Started$startTime (uptime: $uptimeValue) using $usedMemoryValue
  89.             🚀 Served at a JEE Server

  90.             """
  91.     }
  92. }