| 31 import jakarta.servlet.http.Cookie |
31 import jakarta.servlet.http.Cookie |
| 32 import jakarta.servlet.http.HttpServlet |
32 import jakarta.servlet.http.HttpServlet |
| 33 import jakarta.servlet.http.HttpServletRequest |
33 import jakarta.servlet.http.HttpServletRequest |
| 34 import jakarta.servlet.http.HttpServletResponse |
34 import jakarta.servlet.http.HttpServletResponse |
| 35 import java.sql.SQLException |
35 import java.sql.SQLException |
| |
36 import java.time.ZoneId |
| 36 import java.util.* |
37 import java.util.* |
| 37 |
38 |
| 38 abstract class AbstractServlet : HttpServlet() { |
39 abstract class AbstractServlet : HttpServlet() { |
| 39 |
40 |
| 40 companion object { |
41 companion object { |
| |
42 const val COOKIE_MAX_AGE = 2592000 // 30 days |
| 41 const val LANGUAGE_COOKIE_NAME = "lpit_language" |
43 const val LANGUAGE_COOKIE_NAME = "lpit_language" |
| |
44 const val TIMEZONE_COOKIE_NAME = "lpit_timezone" |
| 42 } |
45 } |
| 43 |
46 |
| 44 protected val logger = MyLogger() |
47 protected val logger = MyLogger() |
| 45 |
48 |
| 46 /** |
49 /** |
| 134 ) |
137 ) |
| 135 } else { |
138 } else { |
| 136 val sessionLocale = session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) as Locale |
139 val sessionLocale = session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) as Locale |
| 137 resp.locale = sessionLocale |
140 resp.locale = sessionLocale |
| 138 logger.trace("Continuing session {0} with language {1}", session.id, sessionLocale) |
141 logger.trace("Continuing session {0} with language {1}", session.id, sessionLocale) |
| |
142 } |
| |
143 |
| |
144 // determine the timezone |
| |
145 if (session.getAttribute(Constants.SESSION_ATTR_TIMEZONE) == null) { |
| |
146 // timezone selection stored in cookie |
| |
147 val cookieTimezone = cookieTimezone(http) |
| |
148 |
| |
149 // if no cookie, fall back to server's timezone (the browser does not transmit one) |
| |
150 val timezone = cookieTimezone ?: ZoneId.systemDefault() |
| |
151 |
| |
152 selectTimezone(http, timezone) |
| |
153 logger.debug("Timezone for session {0} set to {1}", session.id, timezone) |
| 139 } |
154 } |
| 140 |
155 |
| 141 // if this is an error path, bypass the normal flow |
156 // if this is an error path, bypass the normal flow |
| 142 if (fullPath.startsWith("/error/")) { |
157 if (fullPath.startsWith("/error/")) { |
| 143 http.styleSheets = listOf("error") |
158 http.styleSheets = listOf("error") |
| 196 |
211 |
| 197 private fun cookieLanguage(http: HttpRequest): Locale? = |
212 private fun cookieLanguage(http: HttpRequest): Locale? = |
| 198 http.request.cookies?.firstOrNull { c -> c.name == LANGUAGE_COOKIE_NAME } |
213 http.request.cookies?.firstOrNull { c -> c.name == LANGUAGE_COOKIE_NAME } |
| 199 ?.runCatching {Locale.forLanguageTag(this.value)}?.getOrNull() |
214 ?.runCatching {Locale.forLanguageTag(this.value)}?.getOrNull() |
| 200 |
215 |
| |
216 protected fun sessionLanguage(http: HttpRequest) = http.session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) as Locale |
| |
217 |
| |
218 private fun cookieTimezone(http: HttpRequest): ZoneId? = |
| |
219 http.request.cookies?.firstOrNull { c -> c.name == TIMEZONE_COOKIE_NAME } |
| |
220 ?.runCatching { ZoneId.of(this.value)}?.getOrNull() |
| |
221 |
| |
222 protected fun sessionTimezone(http: HttpRequest) = http.session.getAttribute(Constants.SESSION_ATTR_TIMEZONE) as String |
| |
223 |
| |
224 protected fun selectTimezone(http: HttpRequest, zoneId: ZoneId) { |
| |
225 http.session.setAttribute(Constants.SESSION_ATTR_TIMEZONE, zoneId.id) |
| |
226 val cookie = Cookie(TIMEZONE_COOKIE_NAME, zoneId.id) |
| |
227 cookie.isHttpOnly = true |
| |
228 cookie.path = http.request.contextPath |
| |
229 cookie.maxAge = COOKIE_MAX_AGE |
| |
230 http.response.addCookie(cookie) |
| |
231 } |
| |
232 |
| 201 protected fun selectLanguage(http: HttpRequest, locale: Locale) { |
233 protected fun selectLanguage(http: HttpRequest, locale: Locale) { |
| 202 http.response.locale = locale |
234 http.response.locale = locale |
| 203 http.session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, locale) |
235 http.session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, locale) |
| 204 // delete cookie if language selection matches request locale, otherwise set cookie |
236 // delete cookie if language selection matches request locale, otherwise set cookie |
| 205 val cookie = Cookie(LANGUAGE_COOKIE_NAME, "") |
237 val cookie = Cookie(LANGUAGE_COOKIE_NAME, "") |
| 207 cookie.path = http.request.contextPath |
239 cookie.path = http.request.contextPath |
| 208 if (http.request.locale.language == locale.language) { |
240 if (http.request.locale.language == locale.language) { |
| 209 cookie.maxAge = 0 |
241 cookie.maxAge = 0 |
| 210 } else { |
242 } else { |
| 211 cookie.value = locale.language |
243 cookie.value = locale.language |
| 212 cookie.maxAge = 2592000 // 30 days |
244 cookie.maxAge = COOKIE_MAX_AGE |
| 213 } |
245 } |
| 214 http.response.addCookie(cookie) |
246 http.response.addCookie(cookie) |
| 215 } |
247 } |
| 216 } |
248 } |