com.hexagonkt.http.server.servlet.ServletServer.kt Maven / Gradle / Ivy
package com.hexagonkt.http.server.servlet
import com.hexagonkt.core.text.AnsiColor.BLUE
import com.hexagonkt.core.text.AnsiEffect.BOLD
import com.hexagonkt.core.text.AnsiColor.CYAN
import com.hexagonkt.core.text.AnsiColor.MAGENTA
import com.hexagonkt.core.text.Ansi.RESET
import com.hexagonkt.core.Jvm
import com.hexagonkt.core.text.prependIndent
import com.hexagonkt.core.require
import com.hexagonkt.core.logging.Logger
import com.hexagonkt.http.server.HttpServer
import com.hexagonkt.http.server.HttpServerSettings
import com.hexagonkt.http.handlers.HttpHandler
import com.hexagonkt.http.handlers.OnHandler
import jakarta.servlet.*
import java.lang.management.ManagementFactory
import java.util.*
/**
* Adapter to run a router inside a Servlets container. It is not a standard engine as it is not
* started/stopped (not passed to an [HttpServer]).
*/
abstract class ServletServer(
private val handler: HttpHandler = OnHandler { this },
private val settings: HttpServerSettings = HttpServerSettings(),
) : ServletContextListener {
private companion object {
val logger: Logger = Logger(ServletServer::class)
}
override fun contextInitialized(sce: ServletContextEvent) {
val startTimestamp = System.nanoTime()
val servletFilter = ServletFilter(handler)
// Let's be a good JEE citizen
val servletContext = sce.servletContext
servletFilter.init(object : FilterConfig {
val params = Hashtable(1).apply { put("filterName", filterName) }
override fun getFilterName(): String = ServletFilter::class.java.name
override fun getServletContext(): ServletContext = servletContext
override fun getInitParameter(name: String): String = params.require(name)
override fun getInitParameterNames(): Enumeration = params.keys()
})
val filter = servletContext.addFilter("filters", servletFilter)
filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType::class.java), true, "/*")
logger.info { "Server started\n${createBanner(System.nanoTime() - startTimestamp)}" }
}
override fun contextDestroyed(sce: ServletContextEvent?) {
logger.info { "Server context destroyed" }
}
private fun createBanner(startUpTimestamp: Long): String {
val heap = ManagementFactory.getMemoryMXBean().heapMemoryUsage
val jvmMemory = "%,d".format(heap.init / 1024)
val usedMemory = "%,d".format(heap.used / 1024)
val bootTime = "%01.3f".format(ManagementFactory.getRuntimeMXBean().uptime / 1e3)
val startUpTime = "%,.0f".format(startUpTimestamp / 1e6)
val serverAdapterValue = "$BOLD$CYAN${javaClass.simpleName}$RESET"
val hostnameValue = "$BLUE${Jvm.hostName}$RESET"
val cpuCountValue = "$BLUE${Jvm.cpuCount}$RESET"
val jvmMemoryValue = "$BLUE$jvmMemory$RESET"
val javaVersionValue = "$BOLD${BLUE}Java ${Jvm.version}$RESET [$BLUE${Jvm.name}$RESET]"
val localeValue = "$BLUE${Jvm.localeCode}$RESET"
val timezoneValue = "$BLUE${Jvm.timeZone.id}$RESET"
val charsetValue = "$BLUE${Jvm.charset}$RESET"
val bootTimeValue = "$BOLD$MAGENTA$bootTime s$RESET"
val startUpTimeValue = "$BOLD$MAGENTA$startUpTime ms$RESET"
val usedMemoryValue = "$BOLD$MAGENTA$usedMemory KB$RESET"
val information = """
Server Adapter: $serverAdapterValue
🖥️️ Running in '$hostnameValue' with $cpuCountValue CPUs $jvmMemoryValue KB
🛠 Using $javaVersionValue
🌍 Locale: $localeValue Timezone: $timezoneValue Charset: $charsetValue
⏱ Started in $bootTimeValue (server: $startUpTimeValue) using $usedMemoryValue
🚀 Served at a JEE Server
""".trimIndent()
val banner = (settings.banner?.let { "$it\n" } ?: HttpServer.banner) + information
return banner.prependIndent()
}
}