001/*
002 * Copyright 2002-2018 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.Map;
021import java.util.TimeZone;
022import javax.servlet.ServletContext;
023import javax.servlet.ServletRequest;
024import javax.servlet.http.HttpServletRequest;
025
026import org.springframework.context.i18n.LocaleContext;
027import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
028import org.springframework.ui.context.Theme;
029import org.springframework.ui.context.ThemeSource;
030import org.springframework.web.context.ContextLoader;
031import org.springframework.web.context.WebApplicationContext;
032import org.springframework.web.context.support.WebApplicationContextUtils;
033import org.springframework.web.servlet.DispatcherServlet;
034import org.springframework.web.servlet.FlashMap;
035import org.springframework.web.servlet.FlashMapManager;
036import org.springframework.web.servlet.LocaleContextResolver;
037import org.springframework.web.servlet.LocaleResolver;
038import org.springframework.web.servlet.ThemeResolver;
039
040/**
041 * Utility class for easy access to request-specific state which has been
042 * set by the {@link org.springframework.web.servlet.DispatcherServlet}.
043 *
044 * <p>Supports lookup of current WebApplicationContext, LocaleResolver,
045 * Locale, ThemeResolver, Theme, and MultipartResolver.
046 *
047 * @author Juergen Hoeller
048 * @author Rossen Stoyanchev
049 * @since 03.03.2003
050 * @see RequestContext
051 * @see org.springframework.web.servlet.DispatcherServlet
052 */
053public abstract class RequestContextUtils {
054
055        /**
056         * The name of the bean to use to look up in an implementation of
057         * {@link RequestDataValueProcessor} has been configured.
058         * @since 4.2.1
059         */
060        public static final String REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME = "requestDataValueProcessor";
061
062
063        /**
064         * Look for the WebApplicationContext associated with the DispatcherServlet
065         * that has initiated request processing.
066         * @param request current HTTP request
067         * @return the request-specific web application context
068         * @throws IllegalStateException if no servlet-specific context has been found
069         * @see #getWebApplicationContext(ServletRequest, ServletContext)
070         * @deprecated as of Spring 4.2.1, in favor of
071         * {@link #findWebApplicationContext(HttpServletRequest)}
072         */
073        @Deprecated
074        public static WebApplicationContext getWebApplicationContext(ServletRequest request) throws IllegalStateException {
075                return getWebApplicationContext(request, null);
076        }
077
078        /**
079         * Look for the WebApplicationContext associated with the DispatcherServlet
080         * that has initiated request processing, and for the global context if none
081         * was found associated with the current request. This method is useful to
082         * allow components outside the framework, such as JSP tag handlers,
083         * to access the most specific application context available.
084         * @param request current HTTP request
085         * @param servletContext current servlet context
086         * @return the request-specific WebApplicationContext, or the global one
087         * if no request-specific context has been found
088         * @throws IllegalStateException if neither a servlet-specific nor a
089         * global context has been found
090         * @see DispatcherServlet#WEB_APPLICATION_CONTEXT_ATTRIBUTE
091         * @see WebApplicationContextUtils#getRequiredWebApplicationContext(ServletContext)
092         * @deprecated as of Spring 4.2.1, in favor of
093         * {@link #findWebApplicationContext(HttpServletRequest, ServletContext)}
094         */
095        @Deprecated
096        public static WebApplicationContext getWebApplicationContext(
097                        ServletRequest request, ServletContext servletContext) throws IllegalStateException {
098
099                WebApplicationContext webApplicationContext = (WebApplicationContext) request.getAttribute(
100                                DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
101                if (webApplicationContext == null) {
102                        if (servletContext == null) {
103                                throw new IllegalStateException("No WebApplicationContext found: not in a DispatcherServlet request?");
104                        }
105                        webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
106                }
107                return webApplicationContext;
108        }
109
110        /**
111         * Look for the WebApplicationContext associated with the DispatcherServlet
112         * that has initiated request processing, and for the global context if none
113         * was found associated with the current request. The global context will
114         * be found via the ServletContext or via ContextLoader's current context.
115         * <p>NOTE: This variant remains compatible with Servlet 2.5, explicitly
116         * checking a given ServletContext instead of deriving it from the request.
117         * @param request current HTTP request
118         * @param servletContext current servlet context
119         * @return the request-specific WebApplicationContext, or the global one
120         * if no request-specific context has been found, or {@code null} if none
121         * @since 4.2.1
122         * @see DispatcherServlet#WEB_APPLICATION_CONTEXT_ATTRIBUTE
123         * @see WebApplicationContextUtils#getWebApplicationContext(ServletContext)
124         * @see ContextLoader#getCurrentWebApplicationContext()
125         */
126        public static WebApplicationContext findWebApplicationContext(
127                        HttpServletRequest request, ServletContext servletContext) {
128
129                WebApplicationContext webApplicationContext = (WebApplicationContext) request.getAttribute(
130                                DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
131                if (webApplicationContext == null) {
132                        if (servletContext != null) {
133                                webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
134                        }
135                        if (webApplicationContext == null) {
136                                webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
137                        }
138                }
139                return webApplicationContext;
140        }
141
142        /**
143         * Look for the WebApplicationContext associated with the DispatcherServlet
144         * that has initiated request processing, and for the global context if none
145         * was found associated with the current request. The global context will
146         * be found via the ServletContext or via ContextLoader's current context.
147         * <p>NOTE: This variant requires Servlet 3.0+ and is generally recommended
148         * for forward-looking custom user code.
149         * @param request current HTTP request
150         * @return the request-specific WebApplicationContext, or the global one
151         * if no request-specific context has been found, or {@code null} if none
152         * @since 4.2.1
153         * @see #findWebApplicationContext(HttpServletRequest, ServletContext)
154         * @see ServletRequest#getServletContext()
155         * @see ContextLoader#getCurrentWebApplicationContext()
156         */
157        public static WebApplicationContext findWebApplicationContext(HttpServletRequest request) {
158                return findWebApplicationContext(request, request.getServletContext());
159        }
160
161        /**
162         * Return the LocaleResolver that has been bound to the request by the
163         * DispatcherServlet.
164         * @param request current HTTP request
165         * @return the current LocaleResolver, or {@code null} if not found
166         */
167        public static LocaleResolver getLocaleResolver(HttpServletRequest request) {
168                return (LocaleResolver) request.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE);
169        }
170
171        /**
172         * Retrieve the current locale from the given request, using the
173         * LocaleResolver bound to the request by the DispatcherServlet
174         * (if available), falling back to the request's accept-header Locale.
175         * <p>This method serves as a straightforward alternative to the standard
176         * Servlet {@link javax.servlet.http.HttpServletRequest#getLocale()} method,
177         * falling back to the latter if no more specific locale has been found.
178         * <p>Consider using {@link org.springframework.context.i18n.LocaleContextHolder#getLocale()}
179         * which will normally be populated with the same Locale.
180         * @param request current HTTP request
181         * @return the current locale for the given request, either from the
182         * LocaleResolver or from the plain request itself
183         * @see #getLocaleResolver
184         * @see org.springframework.context.i18n.LocaleContextHolder#getLocale()
185         */
186        public static Locale getLocale(HttpServletRequest request) {
187                LocaleResolver localeResolver = getLocaleResolver(request);
188                return (localeResolver != null ? localeResolver.resolveLocale(request) : request.getLocale());
189        }
190
191        /**
192         * Retrieve the current time zone from the given request, using the
193         * TimeZoneAwareLocaleResolver bound to the request by the DispatcherServlet
194         * (if available), falling back to the system's default time zone.
195         * <p>Note: This method returns {@code null} if no specific time zone can be
196         * resolved for the given request. This is in contrast to {@link #getLocale}
197         * where there is always the request's accept-header locale to fall back to.
198         * <p>Consider using {@link org.springframework.context.i18n.LocaleContextHolder#getTimeZone()}
199         * which will normally be populated with the same TimeZone: That method only
200         * differs in terms of its fallback to the system time zone if the LocaleResolver
201         * hasn't provided a specific time zone (instead of this method's {@code null}).
202         * @param request current HTTP request
203         * @return the current time zone for the given request, either from the
204         * TimeZoneAwareLocaleResolver or {@code null} if none associated
205         * @see #getLocaleResolver
206         * @see org.springframework.context.i18n.LocaleContextHolder#getTimeZone()
207         */
208        public static TimeZone getTimeZone(HttpServletRequest request) {
209                LocaleResolver localeResolver = getLocaleResolver(request);
210                if (localeResolver instanceof LocaleContextResolver) {
211                        LocaleContext localeContext = ((LocaleContextResolver) localeResolver).resolveLocaleContext(request);
212                        if (localeContext instanceof TimeZoneAwareLocaleContext) {
213                                return ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
214                        }
215                }
216                return null;
217        }
218
219        /**
220         * Return the ThemeResolver that has been bound to the request by the
221         * DispatcherServlet.
222         * @param request current HTTP request
223         * @return the current ThemeResolver, or {@code null} if not found
224         */
225        public static ThemeResolver getThemeResolver(HttpServletRequest request) {
226                return (ThemeResolver) request.getAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE);
227        }
228
229        /**
230         * Return the ThemeSource that has been bound to the request by the
231         * DispatcherServlet.
232         * @param request current HTTP request
233         * @return the current ThemeSource
234         */
235        public static ThemeSource getThemeSource(HttpServletRequest request) {
236                return (ThemeSource) request.getAttribute(DispatcherServlet.THEME_SOURCE_ATTRIBUTE);
237        }
238
239        /**
240         * Retrieves the current theme from the given request, using the ThemeResolver
241         * and ThemeSource bound to the request by the DispatcherServlet.
242         * @param request current HTTP request
243         * @return the current theme, or {@code null} if not found
244         * @see #getThemeResolver
245         */
246        public static Theme getTheme(HttpServletRequest request) {
247                ThemeResolver themeResolver = getThemeResolver(request);
248                ThemeSource themeSource = getThemeSource(request);
249                if (themeResolver != null && themeSource != null) {
250                        String themeName = themeResolver.resolveThemeName(request);
251                        return themeSource.getTheme(themeName);
252                }
253                else {
254                        return null;
255                }
256        }
257
258        /**
259         * Return read-only "input" flash attributes from request before redirect.
260         * @param request current request
261         * @return a read-only Map, or {@code null} if not found
262         * @see FlashMap
263         */
264        @SuppressWarnings("unchecked")
265        public static Map<String, ?> getInputFlashMap(HttpServletRequest request) {
266                return (Map<String, ?>) request.getAttribute(DispatcherServlet.INPUT_FLASH_MAP_ATTRIBUTE);
267        }
268
269        /**
270         * Return "output" FlashMap to save attributes for request after redirect.
271         * @param request current request
272         * @return a {@link FlashMap} instance, never {@code null} within a
273         * {@code DispatcherServlet}-handled request
274         */
275        public static FlashMap getOutputFlashMap(HttpServletRequest request) {
276                return (FlashMap) request.getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE);
277        }
278
279        /**
280         * Return the {@code FlashMapManager} instance to save flash attributes.
281         * @param request the current request
282         * @return a {@link FlashMapManager} instance, never {@code null} within a
283         * {@code DispatcherServlet}-handled request
284         */
285        public static FlashMapManager getFlashMapManager(HttpServletRequest request) {
286                return (FlashMapManager) request.getAttribute(DispatcherServlet.FLASH_MAP_MANAGER_ATTRIBUTE);
287        }
288
289}