All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.web.filter.TimeZoneAwareLocaleChangeFilter Maven / Gradle / Ivy

package org.springframework.web.filter;

import java.io.IOException;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.i18n.SimpleTimeZoneAwareLocaleContext;
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.LocaleContextResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.support.RequestContextUtils;

/**
 * @see RequestContextUtils#getLocaleResolver(HttpServletRequest)
 * @see RequestContextUtils#getLocale(HttpServletRequest)
 * @see LocaleContextHolder#setLocaleContext(org.springframework.context.i18n.LocaleContext)
 * @see org.springframework.beans.propertyeditors.LocaleEditor
 * @see org.springframework.context.i18n.SimpleTimeZoneAwareLocaleContext
 * @see org.springframework.web.servlet.i18n.LocaleChangeInterceptor
 * @see org.springframework.web.servlet.support.RequestContextUtils#getLocale(HttpServletRequest)
 * @see org.springframework.session.web.http.SessionRepositoryFilter#DEFAULT_ORDER
 * @see org.springframework.boot.web.servlet.FilterRegistrationBean#REQUEST_WRAPPER_FILTER_MAX_ORDER
 */
public class TimeZoneAwareLocaleChangeFilter extends OncePerRequestFilter {
  protected final Log logger = LogFactory.getLog(getClass());

  private static final String DEFAULT_LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
  private static final String DEFAULT_TIME_ZONE_PARAM_NAME = "timeZone";
  private static final String DEFAULT_LOCALE_PARAM_NAME = "locale";

  private static final String CONTENT_TIME_ZONE = "Content-Time-Zone";

  private String localeResolverBeanName = DEFAULT_LOCALE_RESOLVER_BEAN_NAME;
  private String timeZoneParamName = DEFAULT_TIME_ZONE_PARAM_NAME;
  private String localeParamName = DEFAULT_LOCALE_PARAM_NAME;

  private boolean header;
  private boolean createSessionAllowed;
  private List httpMethod = new ArrayList();
  private List locale = Arrays.asList(Locale.getDefault());
  private List timeZone = Arrays.asList(TimeZone.getDefault());

  /**
   * @see org.springframework.security.web.savedrequest.HttpSessionRequestCache#saveRequest(HttpServletRequest,
   * HttpServletResponse)
   * @see org.springframework.web.servlet.i18n.SessionLocaleResolver
   * @see org.springframework.web.util.WebUtils#getSessionId(HttpServletRequest)
   */
  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    String newLocale = request.getParameter(getLocaleParamName());
    String newTimeZone = request.getParameter(getTimeZoneParamName());

    Locale previousLocale = LocaleContextHolder.getLocale();
    TimeZone previousTimeZone = LocaleContextHolder.getTimeZone();

    LocaleResolver localeResolver = lookupLocaleResolver(request);
    if (localeResolver instanceof LocaleContextResolver) {
      LocaleContext localeContext = ((LocaleContextResolver) localeResolver).resolveLocaleContext(request);
      if (localeContext instanceof TimeZoneAwareLocaleContext) {
        previousTimeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
      }
      previousLocale = localeContext.getLocale();
    }
    else if (localeResolver instanceof LocaleResolver) {
      previousLocale = localeResolver.resolveLocale(request);
    }

    Locale locale = determineLocale(this.locale, previousLocale);
    TimeZone timeZone = determineTimeZone(this.timeZone, previousTimeZone);

    if (checkHttpMethod(request.getMethod())) {
      if (StringUtils.hasText(newLocale)) {
        locale = determineLocale(this.locale, parseLocaleString(newLocale));
        if (logger.isDebugEnabled()) {
          logger.debug("Input Locale [" + getLocaleParamName() + "]([" + newLocale + "]): " + locale);
        }
      }
      if (StringUtils.hasText(newTimeZone)) {
        timeZone = determineTimeZone(this.timeZone, parseTimeZoneString(newTimeZone));
        if (logger.isDebugEnabled()) {
          logger.debug("Input TimeZone [" + getTimeZoneParamName() + "]([" + newTimeZone + "]): " + timeZone);
        }
      }
    }

    boolean changeLocale = !locale.equals(previousLocale);
    boolean changeTimeZone = !timeZone.equals(previousTimeZone);

    if (changeLocale || changeTimeZone) {
      if (changeLocale && logger.isDebugEnabled()) {
        logger.debug("Change Locale [" + locale + "] from [" + previousLocale + "]");
      }
      if (changeTimeZone && logger.isDebugEnabled()) {
        logger.debug("Change TimeZone [" + timeZone.getID() + "] from [" + (previousTimeZone == null ? null : previousTimeZone.getID()) + "]");
      }

      if (localeResolver instanceof LocaleContextResolver) {
        if (createSessionAllowed || request.getSession(false) != null) {
          ((LocaleContextResolver) localeResolver).setLocaleContext(request, response, new SimpleTimeZoneAwareLocaleContext(locale, timeZone));
        }
      }
      else if (localeResolver instanceof LocaleResolver) {
        localeResolver.setLocale(request, response, locale);
      }
    }

    if (header) {
      if (!response.containsHeader(HttpHeaders.CONTENT_LANGUAGE)) {
        response.addHeader(HttpHeaders.CONTENT_LANGUAGE, locale.toLanguageTag());
      }
      if (!response.containsHeader(CONTENT_TIME_ZONE)) {
        response.addHeader(CONTENT_TIME_ZONE, timeZone.getID());
      }
    }

    filterChain.doFilter(request, response);
  }

  private boolean checkHttpMethod(String currentMethod) {
    List configuredMethods = getHttpMethod();
    if (CollectionUtils.isEmpty(configuredMethods)) {
      return true;
    }
    if (StringUtils.hasText(currentMethod)) {
      for (HttpMethod configuredMethod : configuredMethods) {
        if (configuredMethod.matches(currentMethod.toUpperCase())) {
          return true;
        }
      }
    }
    return false;
  }

  protected LocaleResolver lookupLocaleResolver(HttpServletRequest request) {
    return lookupLocaleResolver();
  }

  protected LocaleResolver lookupLocaleResolver() {
    WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    String beanName = getLocaleResolverBeanName();
    if (wac != null && wac.containsBean(beanName)) {
      if (logger.isDebugEnabled()) {
        logger.debug("Using LocaleResolver '" + beanName + "' for TimeZoneAwareLocaleChangeFilter");
      }
      return wac.getBean(beanName, LocaleResolver.class);
    }
    return null;
  }

  public Locale determineLocale(Collection locales, Locale locale) {
    if (CollectionUtils.isEmpty(locales)) {
      if (locale == null || Locale.ROOT.equals(locale)) {
        locale = LocaleContextHolder.getLocale();
      }
      if (locale == null) {
        locale = Locale.getDefault();
      }
      Assert.notNull(locale, "Not found 'Locale' from System");
      return locale;
    }

    if (locale == null) {
      return locales.iterator().next();
    }

    if (locales.contains(locale)) {
      return locale;
    }

    for (Iterator iterator = locales.iterator(); iterator.hasNext();) {
      Locale next = iterator.next();
      if (locale.getLanguage().equals(next.getLanguage())) {
        return next;
      }
    }
    return locales.iterator().next();
  }

  /**
   * 
   * TimeZone.getTimeZone("")
   * 
   */
  public TimeZone determineTimeZone(Collection timeZones, TimeZone timeZone) {
    if (CollectionUtils.isEmpty(timeZones)) {
      if (timeZone == null || TimeZone.getTimeZone(ZoneOffset.UTC.normalized()).hasSameRules(timeZone)) {
        timeZone = LocaleContextHolder.getTimeZone();
      }
      if (timeZone == null) {
        timeZone = TimeZone.getDefault();
      }
      Assert.notNull(timeZone, "Not found 'TimeZone' from System");
      return timeZone;
    }

    if (timeZone == null) {
      return timeZones.iterator().next();
    }

    if (timeZones.contains(timeZone)) {
      return timeZone;
    }

    for (Iterator iterator = timeZones.iterator(); iterator.hasNext();) {
      TimeZone next = iterator.next();
      if (timeZone.hasSameRules(next)) {
        return next;
      }
    }
    return timeZones.iterator().next();
  }

  /**
   * {@code localeString.replace('-', '_')}
   */
  public Locale parseLocaleString(final String localeString) {
    try {
      Assert.hasText(localeString, "'localeString' must not be empty");
      return StringUtils.parseLocaleString(localeString);
    }
    catch (IllegalArgumentException e) {
      if (logger.isTraceEnabled()) {
        logger.trace("Parse Locale fail... from " + localeString, e);
      }
      else if (logger.isWarnEnabled()) {
        logger.warn("Parse Locale fail... from " + localeString + " (" + e.getMessage() + ")");
      }
      return null;
    }
  }

  public TimeZone parseTimeZoneString(final String timeZoneString) {
    try {
      Assert.hasText(timeZoneString, "'timeZoneString' must not be empty");
      return StringUtils.parseTimeZoneString(timeZoneString);
    }
    catch (IllegalArgumentException e) {
      if (logger.isTraceEnabled()) {
        logger.trace("Parse TimeZone fail... from " + timeZoneString, e);
      }
      else if (logger.isWarnEnabled()) {
        logger.warn("Parse TimeZone fail... from " + timeZoneString + " (" + e.getMessage() + ")");
      }
      return null;
    }
  }

  public String getLocaleResolverBeanName() {
    return localeResolverBeanName;
  }

  public void setLocaleResolverBeanName(String localeResolverBeanName) {
    this.localeResolverBeanName = localeResolverBeanName;
  }

  public String getTimeZoneParamName() {
    return timeZoneParamName;
  }

  public void setTimeZoneParamName(String timeZoneParamName) {
    this.timeZoneParamName = timeZoneParamName;
  }

  public String getLocaleParamName() {
    return localeParamName;
  }

  public void setLocaleParamName(String localeParamName) {
    this.localeParamName = localeParamName;
  }

  public List getHttpMethod() {
    return httpMethod;
  }

  public void setHttpMethod(List httpMethod) {
    this.httpMethod = httpMethod;
  }

  public List getLocale() {
    return locale;
  }

  public void setLocale(List locale) {
    this.locale = locale;
  }

  public List getTimeZone() {
    return timeZone;
  }

  public void setTimeZone(List timeZone) {
    this.timeZone = timeZone;
  }

  public boolean isHeader() {
    return header;
  }

  public void setHeader(boolean header) {
    this.header = header;
  }

  public boolean isCreateSessionAllowed() {
    return createSessionAllowed;
  }

  public void setCreateSessionAllowed(boolean createSessionAllowed) {
    this.createSessionAllowed = createSessionAllowed;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy