/**
   * Initialize this context with the given request, using the given model attributes for Errors
   * retrieval.
   *
   * <p>Delegates to {@code getFallbackLocale} and {@code getFallbackTheme} for determining the
   * fallback locale and theme, respectively, if no LocaleResolver and/or ThemeResolver can be found
   * in the request.
   *
   * @param request current HTTP request
   * @param servletContext the servlet context of the web application (can be {@code null};
   *     necessary for fallback to root WebApplicationContext)
   * @param model the model attributes for the current view (can be {@code null}, using the request
   *     attributes for Errors retrieval)
   * @see #getFallbackLocale
   * @see #getFallbackTheme
   * @see org.springframework.web.servlet.DispatcherServlet#LOCALE_RESOLVER_ATTRIBUTE
   * @see org.springframework.web.servlet.DispatcherServlet#THEME_RESOLVER_ATTRIBUTE
   */
  protected void initContext(
      HttpServletRequest request,
      HttpServletResponse response,
      ServletContext servletContext,
      Map<String, Object> model) {

    this.request = request;
    this.response = response;
    this.model = model;

    // Fetch WebApplicationContext, either from DispatcherServlet or the root context.
    // ServletContext needs to be specified to be able to fall back to the root context!
    this.webApplicationContext =
        (WebApplicationContext) request.getAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    if (this.webApplicationContext == null) {
      this.webApplicationContext =
          RequestContextUtils.getWebApplicationContext(request, servletContext);
    }

    // Determine locale to use for this RequestContext.
    LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
    if (localeResolver instanceof LocaleContextResolver) {
      LocaleContext localeContext =
          ((LocaleContextResolver) localeResolver).resolveLocaleContext(request);
      this.locale = localeContext.getLocale();
      if (localeContext instanceof TimeZoneAwareLocaleContext) {
        this.timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
      }
    } else if (localeResolver != null) {
      // Try LocaleResolver (we're within a DispatcherServlet request).
      this.locale = localeResolver.resolveLocale(request);
    }

    // Try JSTL fallbacks if necessary.
    if (this.locale == null) {
      this.locale = getFallbackLocale();
    }
    if (this.timeZone == null) {
      this.timeZone = getFallbackTimeZone();
    }

    // Determine default HTML escape setting from the "defaultHtmlEscape"
    // context-param in web.xml, if any.
    this.defaultHtmlEscape =
        WebUtils.getDefaultHtmlEscape(this.webApplicationContext.getServletContext());

    // Determine response-encoded HTML escape setting from the "responseEncodedHtmlEscape"
    // context-param in web.xml, if any.
    this.responseEncodedHtmlEscape =
        WebUtils.getResponseEncodedHtmlEscape(this.webApplicationContext.getServletContext());

    this.urlPathHelper = new UrlPathHelper();

    if (this.webApplicationContext.containsBean(REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME)) {
      this.requestDataValueProcessor =
          this.webApplicationContext.getBean(
              REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME, RequestDataValueProcessor.class);
    }
  }
 /**
  * Change the current locale to the specified one, storing the new locale through the configured
  * {@link LocaleResolver}.
  *
  * @param locale the new locale
  * @see LocaleResolver#setLocale
  * @see #changeLocale(java.util.Locale, java.util.TimeZone)
  */
 public void changeLocale(Locale locale) {
   LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(this.request);
   if (localeResolver == null) {
     throw new IllegalStateException("Cannot change locale if no LocaleResolver configured");
   }
   localeResolver.setLocale(this.request, this.response, locale);
   this.locale = locale;
 }
 /**
  * Change the current theme to the specified theme by name, storing the new theme name through the
  * configured {@link ThemeResolver}.
  *
  * @param themeName the name of the new theme
  * @see ThemeResolver#setThemeName
  */
 public void changeTheme(String themeName) {
   ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(this.request);
   if (themeResolver == null) {
     throw new IllegalStateException("Cannot change theme if no ThemeResolver configured");
   }
   themeResolver.setThemeName(this.request, this.response, themeName);
   // Ask for re-resolution on next getTheme call.
   this.theme = null;
 }
 /**
  * Change the current theme to the specified one, storing the new theme name through the
  * configured {@link ThemeResolver}.
  *
  * @param theme the new theme
  * @see ThemeResolver#setThemeName
  */
 public void changeTheme(Theme theme) {
   ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(this.request);
   if (themeResolver == null) {
     throw new IllegalStateException("Cannot change theme if no ThemeResolver configured");
   }
   themeResolver.setThemeName(
       this.request, this.response, (theme != null ? theme.getName() : null));
   this.theme = theme;
 }
 /**
  * Return the current theme (never {@code null}).
  *
  * <p>Resolved lazily for more efficiency when theme support is not being used.
  */
 public Theme getTheme() {
   if (this.theme == null) {
     // Lazily determine theme to use for this RequestContext.
     this.theme = RequestContextUtils.getTheme(this.request);
     if (this.theme == null) {
       // No ThemeResolver and ThemeSource available -> try fallback.
       this.theme = getFallbackTheme();
     }
   }
   return this.theme;
 }
 /**
  * Determine the fallback theme for this context.
  *
  * <p>The default implementation returns the default theme (with name "theme").
  *
  * @return the fallback theme (never {@code null})
  */
 protected Theme getFallbackTheme() {
   ThemeSource themeSource = RequestContextUtils.getThemeSource(getRequest());
   if (themeSource == null) {
     themeSource = new ResourceBundleThemeSource();
   }
   Theme theme = themeSource.getTheme(DEFAULT_THEME_NAME);
   if (theme == null) {
     throw new IllegalStateException("No theme defined and no fallback theme found");
   }
   return theme;
 }
 /**
  * Change the current locale to the specified locale and time zone context, storing the new locale
  * context through the configured {@link LocaleResolver}.
  *
  * @param locale the new locale
  * @param timeZone the new time zone
  * @see LocaleContextResolver#setLocaleContext
  * @see org.springframework.context.i18n.SimpleTimeZoneAwareLocaleContext
  */
 public void changeLocale(Locale locale, TimeZone timeZone) {
   LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(this.request);
   if (!(localeResolver instanceof LocaleContextResolver)) {
     throw new IllegalStateException(
         "Cannot change locale context if no LocaleContextResolver configured");
   }
   ((LocaleContextResolver) localeResolver)
       .setLocaleContext(
           this.request, this.response, new SimpleTimeZoneAwareLocaleContext(locale, timeZone));
   this.locale = locale;
   this.timeZone = timeZone;
 }