src/main/kotlin/de/uapcore/lightpit/AbstractServlet.kt

changeset 298
1275eb652008
parent 254
55ca6cafc3dd
     1.1 --- a/src/main/kotlin/de/uapcore/lightpit/AbstractServlet.kt	Fri Nov 24 00:07:36 2023 +0100
     1.2 +++ b/src/main/kotlin/de/uapcore/lightpit/AbstractServlet.kt	Sat Jan 06 20:31:14 2024 +0100
     1.3 @@ -28,6 +28,7 @@
     1.4  import de.uapcore.lightpit.DataSourceProvider.Companion.SC_ATTR_NAME
     1.5  import de.uapcore.lightpit.dao.DataAccessObject
     1.6  import de.uapcore.lightpit.dao.createDataAccessObject
     1.7 +import jakarta.servlet.http.Cookie
     1.8  import jakarta.servlet.http.HttpServlet
     1.9  import jakarta.servlet.http.HttpServletRequest
    1.10  import jakarta.servlet.http.HttpServletResponse
    1.11 @@ -35,6 +36,10 @@
    1.12  import java.util.*
    1.13  
    1.14  abstract class AbstractServlet : HttpServlet() {
    1.15 +
    1.16 +    companion object {
    1.17 +        const val LANGUAGE_COOKIE_NAME = "lpit_language"
    1.18 +    }
    1.19      
    1.20      protected val logger = MyLogger()
    1.21  
    1.22 @@ -100,22 +105,6 @@
    1.23          // the very first thing to do is to force UTF-8
    1.24          req.characterEncoding = "UTF-8"
    1.25  
    1.26 -        // choose the requested language as session language (if available) or fall back to english, otherwise
    1.27 -        if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) {
    1.28 -            val availableLanguages = availableLanguages()
    1.29 -            val reqLocale = req.locale
    1.30 -            val sessionLocale = if (availableLanguages.contains(reqLocale)) reqLocale else availableLanguages.first()
    1.31 -            session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, sessionLocale)
    1.32 -            resp.locale = sessionLocale
    1.33 -            logger.debug(
    1.34 -                "Setting language for new session {0}: {1}", session.id, sessionLocale.displayLanguage
    1.35 -            )
    1.36 -        } else {
    1.37 -            val sessionLocale = session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) as Locale
    1.38 -            resp.locale = sessionLocale
    1.39 -            logger.trace("Continuing session {0} with language {1}", session.id, sessionLocale)
    1.40 -        }
    1.41 -
    1.42          // set some internal request attributes
    1.43          val http = HttpRequest(req, resp)
    1.44          val fullPath = req.servletPath + Optional.ofNullable(req.pathInfo).orElse("")
    1.45 @@ -126,6 +115,29 @@
    1.46              req.setAttribute(Constants.REQ_ATTR_REFERER, it)
    1.47          }
    1.48  
    1.49 +        // choose the requested language as session language (if available)
    1.50 +        if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) {
    1.51 +            // language selection stored in cookie
    1.52 +            val cookieLocale = cookieLanguage(http)
    1.53 +
    1.54 +            // if no cookie, fall back to request locale a.k.a "Browser Language"
    1.55 +            val reqLocale = cookieLocale ?: req.locale
    1.56 +
    1.57 +            val availableLanguages = availableLanguages()
    1.58 +            val sessionLocale = if (availableLanguages.contains(reqLocale)) reqLocale else availableLanguages.first()
    1.59 +
    1.60 +            // select the language (this will also refresh the cookie max-age)
    1.61 +            selectLanguage(http, sessionLocale)
    1.62 +
    1.63 +            logger.debug(
    1.64 +                "Setting language for new session {0}: {1}", session.id, sessionLocale.displayLanguage
    1.65 +            )
    1.66 +        } else {
    1.67 +            val sessionLocale = session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) as Locale
    1.68 +            resp.locale = sessionLocale
    1.69 +            logger.trace("Continuing session {0} with language {1}", session.id, sessionLocale)
    1.70 +        }
    1.71 +
    1.72          // if this is an error path, bypass the normal flow
    1.73          if (fullPath.startsWith("/error/")) {
    1.74              http.styleSheets = listOf("error")
    1.75 @@ -182,4 +194,23 @@
    1.76          return locales.ifEmpty { listOf(Locale.ENGLISH) }
    1.77      }
    1.78  
    1.79 +    private fun cookieLanguage(http: HttpRequest): Locale? =
    1.80 +        http.request.cookies?.firstOrNull { c -> c.name == LANGUAGE_COOKIE_NAME }
    1.81 +            ?.runCatching {Locale.forLanguageTag(this.value)}?.getOrNull()
    1.82 +
    1.83 +    protected fun selectLanguage(http: HttpRequest, locale: Locale) {
    1.84 +        http.response.locale = locale
    1.85 +        http.session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, locale)
    1.86 +        // delete cookie if language selection matches request locale, otherwise set cookie
    1.87 +        val cookie = Cookie(LANGUAGE_COOKIE_NAME, "")
    1.88 +        cookie.isHttpOnly = true
    1.89 +        cookie.path = http.request.contextPath
    1.90 +        if (http.request.locale.language == locale.language) {
    1.91 +            cookie.maxAge = 0
    1.92 +        } else {
    1.93 +            cookie.value = locale.language
    1.94 +            cookie.maxAge = 2592000 // 30 days
    1.95 +        }
    1.96 +        http.response.addCookie(cookie)
    1.97 +    }
    1.98  }

mercurial