001/* 002 * Copyright 2002-2013 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.support; 018 019import java.util.Locale; 020import java.util.ResourceBundle; 021import java.util.TimeZone; 022import javax.servlet.ServletContext; 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.HttpSession; 025import javax.servlet.jsp.jstl.core.Config; 026import javax.servlet.jsp.jstl.fmt.LocalizationContext; 027 028import org.springframework.context.MessageSource; 029import org.springframework.context.support.MessageSourceResourceBundle; 030import org.springframework.context.support.ResourceBundleMessageSource; 031 032/** 033 * Helper class for preparing JSTL views, 034 * in particular for exposing a JSTL localization context. 035 * 036 * @author Juergen Hoeller 037 * @since 20.08.2003 038 */ 039public abstract class JstlUtils { 040 041 /** 042 * Checks JSTL's "javax.servlet.jsp.jstl.fmt.localizationContext" 043 * context-param and creates a corresponding child message source, 044 * with the provided Spring-defined MessageSource as parent. 045 * @param servletContext the ServletContext we're running in 046 * (to check JSTL-related context-params in {@code web.xml}) 047 * @param messageSource the MessageSource to expose, typically 048 * the ApplicationContext of the current DispatcherServlet 049 * @return the MessageSource to expose to JSTL; first checking the 050 * JSTL-defined bundle, then the Spring-defined MessageSource 051 * @see org.springframework.context.ApplicationContext 052 */ 053 public static MessageSource getJstlAwareMessageSource( 054 ServletContext servletContext, MessageSource messageSource) { 055 056 if (servletContext != null) { 057 String jstlInitParam = servletContext.getInitParameter(Config.FMT_LOCALIZATION_CONTEXT); 058 if (jstlInitParam != null) { 059 // Create a ResourceBundleMessageSource for the specified resource bundle 060 // basename in the JSTL context-param in web.xml, wiring it with the given 061 // Spring-defined MessageSource as parent. 062 ResourceBundleMessageSource jstlBundleWrapper = new ResourceBundleMessageSource(); 063 jstlBundleWrapper.setBasename(jstlInitParam); 064 jstlBundleWrapper.setParentMessageSource(messageSource); 065 return jstlBundleWrapper; 066 } 067 } 068 return messageSource; 069 } 070 071 /** 072 * Exposes JSTL-specific request attributes specifying locale 073 * and resource bundle for JSTL's formatting and message tags, 074 * using Spring's locale and MessageSource. 075 * @param request the current HTTP request 076 * @param messageSource the MessageSource to expose, 077 * typically the current ApplicationContext (may be {@code null}) 078 * @see #exposeLocalizationContext(RequestContext) 079 */ 080 public static void exposeLocalizationContext(HttpServletRequest request, MessageSource messageSource) { 081 Locale jstlLocale = RequestContextUtils.getLocale(request); 082 Config.set(request, Config.FMT_LOCALE, jstlLocale); 083 TimeZone timeZone = RequestContextUtils.getTimeZone(request); 084 if (timeZone != null) { 085 Config.set(request, Config.FMT_TIME_ZONE, timeZone); 086 } 087 if (messageSource != null) { 088 LocalizationContext jstlContext = new SpringLocalizationContext(messageSource, request); 089 Config.set(request, Config.FMT_LOCALIZATION_CONTEXT, jstlContext); 090 } 091 } 092 093 /** 094 * Exposes JSTL-specific request attributes specifying locale 095 * and resource bundle for JSTL's formatting and message tags, 096 * using Spring's locale and MessageSource. 097 * @param requestContext the context for the current HTTP request, 098 * including the ApplicationContext to expose as MessageSource 099 */ 100 public static void exposeLocalizationContext(RequestContext requestContext) { 101 Config.set(requestContext.getRequest(), Config.FMT_LOCALE, requestContext.getLocale()); 102 TimeZone timeZone = requestContext.getTimeZone(); 103 if (timeZone != null) { 104 Config.set(requestContext.getRequest(), Config.FMT_TIME_ZONE, timeZone); 105 } 106 MessageSource messageSource = getJstlAwareMessageSource( 107 requestContext.getServletContext(), requestContext.getMessageSource()); 108 LocalizationContext jstlContext = new SpringLocalizationContext(messageSource, requestContext.getRequest()); 109 Config.set(requestContext.getRequest(), Config.FMT_LOCALIZATION_CONTEXT, jstlContext); 110 } 111 112 113 /** 114 * Spring-specific LocalizationContext adapter that merges session-scoped 115 * JSTL LocalizationContext/Locale attributes with the local Spring request context. 116 */ 117 private static class SpringLocalizationContext extends LocalizationContext { 118 119 private final MessageSource messageSource; 120 121 private final HttpServletRequest request; 122 123 public SpringLocalizationContext(MessageSource messageSource, HttpServletRequest request) { 124 this.messageSource = messageSource; 125 this.request = request; 126 } 127 128 @Override 129 public ResourceBundle getResourceBundle() { 130 HttpSession session = this.request.getSession(false); 131 if (session != null) { 132 Object lcObject = Config.get(session, Config.FMT_LOCALIZATION_CONTEXT); 133 if (lcObject instanceof LocalizationContext) { 134 ResourceBundle lcBundle = ((LocalizationContext) lcObject).getResourceBundle(); 135 return new MessageSourceResourceBundle(this.messageSource, getLocale(), lcBundle); 136 } 137 } 138 return new MessageSourceResourceBundle(this.messageSource, getLocale()); 139 } 140 141 @Override 142 public Locale getLocale() { 143 HttpSession session = this.request.getSession(false); 144 if (session != null) { 145 Object localeObject = Config.get(session, Config.FMT_LOCALE); 146 if (localeObject instanceof Locale) { 147 return (Locale) localeObject; 148 } 149 } 150 return RequestContextUtils.getLocale(this.request); 151 } 152 } 153 154}