001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.web.servlet.support;
018:
019: import java.util.HashMap;
020: import java.util.List;
021: import java.util.Locale;
022: import java.util.Map;
023:
024: import javax.servlet.ServletContext;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpSession;
027:
028: import org.springframework.context.MessageSourceResolvable;
029: import org.springframework.context.NoSuchMessageException;
030: import org.springframework.context.support.StaticMessageSource;
031: import org.springframework.ui.context.Theme;
032: import org.springframework.ui.context.ThemeSource;
033: import org.springframework.ui.context.support.SimpleTheme;
034: import org.springframework.validation.BindException;
035: import org.springframework.validation.BindingResult;
036: import org.springframework.validation.Errors;
037: import org.springframework.web.bind.EscapedErrors;
038: import org.springframework.web.context.WebApplicationContext;
039: import org.springframework.web.servlet.LocaleResolver;
040: import org.springframework.web.util.HtmlUtils;
041: import org.springframework.web.util.UrlPathHelper;
042: import org.springframework.web.util.WebUtils;
043:
044: /**
045: * Context holder for request-specific state, like current web application
046: * context, current locale, current theme, and potential binding errors.
047: * Provides easy access to localized messages and Errors instances.
048: *
049: * <p>Suitable for exposition to views, and usage within JSP's "useBean" tag,
050: * JSP scriptlets, JSTL EL, Velocity templates, etc. Necessary for views
051: * that do not have access to the servlet request, like Velocity templates.
052: *
053: * <p>Can be instantiated manually, or automatically exposed to views as
054: * model attribute via AbstractView's "requestContextAttribute" property.
055: *
056: * <p>Will also work outside DispatcherServlet requests, accessing the root
057: * WebApplicationContext and using an appropriate fallback for the locale
058: * (the JSTL locale if available, or the HttpServletRequest locale else).
059: *
060: * @author Juergen Hoeller
061: * @since 03.03.2003
062: * @see org.springframework.web.servlet.DispatcherServlet
063: * @see org.springframework.web.servlet.view.AbstractView#setRequestContextAttribute
064: * @see org.springframework.web.servlet.view.UrlBasedViewResolver#setRequestContextAttribute
065: * @see #getFallbackLocale
066: */
067: public class RequestContext {
068:
069: /**
070: * Default theme name used if the RequestContext cannot find a ThemeResolver.
071: * Only applies to non-DispatcherServlet requests.
072: * <p>Same as AbstractThemeResolver's default, but not linked in here to
073: * avoid package interdependencies.
074: * @see org.springframework.web.servlet.theme.AbstractThemeResolver#ORIGINAL_DEFAULT_THEME_NAME
075: */
076: public final static String DEFAULT_THEME_NAME = "theme";
077:
078: /**
079: * Default (empty) Theme used if the RequestContext cannot find a ThemeSource.
080: */
081: public final static Theme DEFAULT_THEME = new SimpleTheme(
082: DEFAULT_THEME_NAME, new StaticMessageSource());
083:
084: /**
085: * JSTL locale attribute, as used by JSTL implementations to expose their
086: * current locale. Used as fallback in non-DispatcherServlet requests; if not
087: * available, the accept-header locale is used (<code>request.getLocale</code).
088: * <p>Same as the FMT_LOCALE constant in JSTL's Config class, but not linked
089: * in here to avoid a hard-coded dependency on JSTL. RequestContext does not
090: * depend on JSTL except for this fallback check of JSTL's locale attribute.
091: * @see javax.servlet.jsp.jstl.core.Config#FMT_LOCALE
092: * @see javax.servlet.http.HttpServletRequest#getLocale
093: */
094: public final static String JSTL_LOCALE_ATTRIBUTE = "javax.servlet.jsp.jstl.fmt.locale";
095:
096: /** JSTL suffix for request-scoped attributes */
097: protected static final String REQUEST_SCOPE_SUFFIX = ".request";
098:
099: /** JSTL suffix for session-scoped attributes */
100: protected static final String SESSION_SCOPE_SUFFIX = ".session";
101:
102: /** JSTL suffix for application-scoped attributes */
103: protected static final String APPLICATION_SCOPE_SUFFIX = ".application";
104:
105: private HttpServletRequest request;
106:
107: private Map model;
108:
109: private WebApplicationContext webApplicationContext;
110:
111: private Locale locale;
112:
113: private Theme theme;
114:
115: private boolean defaultHtmlEscape;
116:
117: private UrlPathHelper urlPathHelper;
118:
119: private Map errorsMap;
120:
121: /**
122: * Create a new RequestContext for the given request,
123: * using the request attributes for Errors retrieval.
124: * <p>This only works with InternalResourceViews, as Errors instances
125: * are part of the model and not normally exposed as request attributes.
126: * It will typically be used within JSPs or custom tags.
127: * <p><b>Will only work within a DispatcherServlet request.</b> Pass in a
128: * ServletContext to be able to fallback to the root WebApplicationContext.
129: * @param request current HTTP request
130: * @see org.springframework.web.servlet.DispatcherServlet
131: * @see #RequestContext(javax.servlet.http.HttpServletRequest, javax.servlet.ServletContext)
132: */
133: public RequestContext(HttpServletRequest request) {
134: initContext(request, null, null);
135: }
136:
137: /**
138: * Create a new RequestContext for the given request,
139: * using the request attributes for Errors retrieval.
140: * <p>This only works with InternalResourceViews, as Errors instances
141: * are part of the model and not normally exposed as request attributes.
142: * It will typically be used within JSPs or custom tags.
143: * <p>If a ServletContext is specified, the RequestContext will also
144: * work with the root WebApplicationContext (outside a DispatcherServlet).
145: * @param request current HTTP request
146: * @param servletContext the servlet context of the web application
147: * (can be <code>null</code>; necessary for fallback to root WebApplicationContext)
148: * @see org.springframework.web.context.WebApplicationContext
149: * @see org.springframework.web.servlet.DispatcherServlet
150: */
151: public RequestContext(HttpServletRequest request,
152: ServletContext servletContext) {
153: initContext(request, servletContext, null);
154: }
155:
156: /**
157: * Create a new RequestContext for the given request,
158: * using the given model attributes for Errors retrieval.
159: * <p>This works with all View implementations.
160: * It will typically be used by View implementations.
161: * <p><b>Will only work within a DispatcherServlet request.</b> Pass in a
162: * ServletContext to be able to fallback to the root WebApplicationContext.
163: * @param request current HTTP request
164: * @param model the model attributes for the current view
165: * (can be <code>null</code>, using the request attributes for Errors retrieval)
166: * @see org.springframework.web.servlet.DispatcherServlet
167: * @see #RequestContext(javax.servlet.http.HttpServletRequest, javax.servlet.ServletContext, Map)
168: */
169: public RequestContext(HttpServletRequest request, Map model) {
170: initContext(request, null, model);
171: }
172:
173: /**
174: * Create a new RequestContext for the given request,
175: * using the given model attributes for Errors retrieval.
176: * <p>This works with all View implementations.
177: * It will typically be used by View implementations.
178: * <p>If a ServletContext is specified, the RequestContext will also
179: * work with a root WebApplicationContext (outside a DispatcherServlet).
180: * @param request current HTTP request
181: * @param servletContext the servlet context of the web application
182: * (can be <code>null</code>; necessary for fallback to root WebApplicationContext)
183: * @param model the model attributes for the current view
184: * (can be <code>null</code>, using the request attributes for Errors retrieval)
185: * @see org.springframework.web.context.WebApplicationContext
186: * @see org.springframework.web.servlet.DispatcherServlet
187: */
188: public RequestContext(HttpServletRequest request,
189: ServletContext servletContext, Map model) {
190: initContext(request, servletContext, model);
191: }
192:
193: /**
194: * Default constructor for subclasses.
195: */
196: protected RequestContext() {
197: }
198:
199: /**
200: * Initialize this context with the given request,
201: * using the given model attributes for Errors retrieval.
202: * <p>Delegates to <code>getFallbackLocale</code> and <code>getFallbackTheme</code>
203: * for determining the fallback locale and theme, respectively, if no LocaleResolver
204: * and/or ThemeResolver can be found in the request.
205: * @param request current HTTP request
206: * @param servletContext the servlet context of the web application
207: * (can be <code>null</code>; necessary for fallback to root WebApplicationContext)
208: * @param model the model attributes for the current view
209: * (can be <code>null</code>, using the request attributes for Errors retrieval)
210: * @see #getFallbackLocale
211: * @see #getFallbackTheme
212: * @see org.springframework.web.servlet.DispatcherServlet#LOCALE_RESOLVER_ATTRIBUTE
213: * @see org.springframework.web.servlet.DispatcherServlet#THEME_RESOLVER_ATTRIBUTE
214: */
215: protected void initContext(HttpServletRequest request,
216: ServletContext servletContext, Map model) {
217: this .request = request;
218: this .model = model;
219:
220: // Fetch WebApplicationContext, either from DispatcherServlet or the root context.
221: // ServletContext needs to be specified to be able to fall back to the root context!
222: this .webApplicationContext = RequestContextUtils
223: .getWebApplicationContext(request, servletContext);
224:
225: // Determine locale to use for this RequestContext.
226: LocaleResolver localeResolver = RequestContextUtils
227: .getLocaleResolver(request);
228: if (localeResolver != null) {
229: // Try LocaleResolver (we're within a DispatcherServlet request).
230: this .locale = localeResolver.resolveLocale(request);
231: } else {
232: // No LocaleResolver available -> try fallback.
233: this .locale = getFallbackLocale();
234: }
235:
236: // Determine theme to use for this RequestContext.
237: this .theme = RequestContextUtils.getTheme(request);
238: if (this .theme == null) {
239: // No ThemeResolver and ThemeSource available -> try fallback.
240: this .theme = getFallbackTheme();
241: }
242:
243: // Determine default HTML escape setting from the "defaultHtmlEscape"
244: // context-param in web.xml, if any.
245: this .defaultHtmlEscape = WebUtils
246: .isDefaultHtmlEscape(this .webApplicationContext
247: .getServletContext());
248:
249: this .urlPathHelper = new UrlPathHelper();
250: }
251:
252: /**
253: * Determine the fallback locale for this context.
254: * <p>The default implementation checks for a JSTL locale attribute
255: * in request, session or application scope; if not found,
256: * returns the <code>HttpServletRequest.getLocale()</code>.
257: * @return the fallback locale (never <code>null</code>)
258: * @see javax.servlet.http.HttpServletRequest#getLocale
259: */
260: protected Locale getFallbackLocale() {
261: Locale locale = (Locale) getRequest().getAttribute(
262: JSTL_LOCALE_ATTRIBUTE);
263: if (locale == null) {
264: locale = (Locale) getRequest().getAttribute(
265: JSTL_LOCALE_ATTRIBUTE + REQUEST_SCOPE_SUFFIX);
266: if (locale == null) {
267: HttpSession session = getRequest().getSession(false);
268: if (session != null) {
269: locale = (Locale) session
270: .getAttribute(JSTL_LOCALE_ATTRIBUTE);
271: if (locale == null) {
272: locale = (Locale) session
273: .getAttribute(JSTL_LOCALE_ATTRIBUTE
274: + SESSION_SCOPE_SUFFIX);
275: }
276: }
277: if (locale == null) {
278: locale = (Locale) getServletContext().getAttribute(
279: JSTL_LOCALE_ATTRIBUTE);
280: if (locale == null) {
281: locale = (Locale) getServletContext()
282: .getAttribute(
283: JSTL_LOCALE_ATTRIBUTE
284: + APPLICATION_SCOPE_SUFFIX);
285: if (locale == null) {
286: // No JSTL locale available -> fall back to accept-header locale.
287: locale = getRequest().getLocale();
288: }
289: }
290: }
291: }
292: }
293: return locale;
294: }
295:
296: /**
297: * Determine the fallback theme for this context.
298: * <p>The default implementation returns the default theme (with name "theme").
299: * @return the fallback theme, or <code>null
300: */
301: protected Theme getFallbackTheme() {
302: ThemeSource themeSource = RequestContextUtils
303: .getThemeSource(getRequest());
304: if (themeSource != null) {
305: return themeSource.getTheme(DEFAULT_THEME_NAME);
306: } else {
307: return DEFAULT_THEME;
308: }
309: }
310:
311: /**
312: * Return the underlying HttpServletRequest.
313: * Only intended for cooperating classes in this package.
314: */
315: protected final HttpServletRequest getRequest() {
316: return this .request;
317: }
318:
319: /**
320: * Return the current WebApplicationContext.
321: */
322: public final WebApplicationContext getWebApplicationContext() {
323: return this .webApplicationContext;
324: }
325:
326: /**
327: * Return the underlying ServletContext.
328: * Only intended for cooperating classes in this package.
329: */
330: protected final ServletContext getServletContext() {
331: return this .webApplicationContext.getServletContext();
332: }
333:
334: /**
335: * Return the current locale.
336: */
337: public final Locale getLocale() {
338: return this .locale;
339: }
340:
341: /**
342: * Return the current theme.
343: */
344: public final Theme getTheme() {
345: return this .theme;
346: }
347:
348: /**
349: * (De)activate default HTML escaping for messages and errors, for the scope
350: * of this RequestContext. The default is the application-wide setting
351: * (the "defaultHtmlEscape" context-param in web.xml).
352: * @see org.springframework.web.util.WebUtils#isDefaultHtmlEscape
353: */
354: public void setDefaultHtmlEscape(boolean defaultHtmlEscape) {
355: this .defaultHtmlEscape = defaultHtmlEscape;
356: }
357:
358: /**
359: * Is default HTML escaping active?
360: */
361: public boolean isDefaultHtmlEscape() {
362: return this .defaultHtmlEscape;
363: }
364:
365: /**
366: * Set the UrlPathHelper to use for context path and request URI decoding.
367: * Can be used to pass a shared UrlPathHelper instance in.
368: * <p>A default UrlPathHelper is always available.
369: */
370: public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
371: this .urlPathHelper = (urlPathHelper != null ? urlPathHelper
372: : new UrlPathHelper());
373: }
374:
375: /**
376: * Return the UrlPathHelper used for context path and request URI decoding.
377: * Can be used to configure the current UrlPathHelper.
378: * <p>A default UrlPathHelper is always available.
379: */
380: public UrlPathHelper getUrlPathHelper() {
381: return this .urlPathHelper;
382: }
383:
384: /**
385: * Return the context path of the original request,
386: * that is, the path that indicates the current web application.
387: * This is useful for building links to other resources within the application.
388: * <p>Delegates to the UrlPathHelper for decoding.
389: * @see javax.servlet.http.HttpServletRequest#getContextPath
390: * @see #getUrlPathHelper
391: */
392: public String getContextPath() {
393: return this .urlPathHelper
394: .getOriginatingContextPath(this .request);
395: }
396:
397: /**
398: * Return the request URI of the original request, that is, the invoked URL
399: * without parameters. This is particularly useful as HTML form action target,
400: * possibly in combination with the original query string.
401: * <p><b>Note this implementation will correctly resolve to the URI of any
402: * originating root request in the presence of a forwarded request. However, this
403: * can only work when the Servlet 2.4 'forward' request attributes are present.
404: * For use in a Servlet 2.3- environment, you can rely on
405: * {@link org.springframework.web.servlet.view.InternalResourceView}
406: * to add these prior to dispatching the request.</b>
407: * <p>Delegates to the UrlPathHelper for decoding.
408: * @see #getQueryString
409: * @see org.springframework.web.util.UrlPathHelper#getOriginatingRequestUri
410: * @see #getUrlPathHelper
411: */
412: public String getRequestUri() {
413: return this .urlPathHelper
414: .getOriginatingRequestUri(this .request);
415: }
416:
417: /**
418: * Return the query string of the current request, that is, the part after
419: * the request path. This is particularly useful for building an HTML form
420: * action target in combination with the original request URI.
421: * <p><b>Note this implementation will correctly resolve to the query string of any
422: * originating root request in the presence of a forwarded request. However, this
423: * can only work when the Servlet 2.4 'forward' request attributes are present.
424: * For use in a Servlet 2.3- environment, you can rely on
425: * {@link org.springframework.web.servlet.view.InternalResourceView}
426: * to add these prior to dispatching the request.</b>
427: * <p>Delegates to the UrlPathHelper for decoding.
428: * @see #getRequestUri
429: * @see org.springframework.web.util.UrlPathHelper#getOriginatingQueryString
430: * @see #getUrlPathHelper
431: */
432: public String getQueryString() {
433: return this .urlPathHelper
434: .getOriginatingQueryString(this .request);
435: }
436:
437: /**
438: * Retrieve the message for the given code, using the "defaultHtmlEscape" setting.
439: * @param code code of the message
440: * @param defaultMessage String to return if the lookup fails
441: * @return the message
442: */
443: public String getMessage(String code, String defaultMessage) {
444: return getMessage(code, null, defaultMessage,
445: this .defaultHtmlEscape);
446: }
447:
448: /**
449: * Retrieve the message for the given code, using the "defaultHtmlEscape" setting.
450: * @param code code of the message
451: * @param args arguments for the message, or <code>null</code> if none
452: * @param defaultMessage String to return if the lookup fails
453: * @return the message
454: */
455: public String getMessage(String code, Object[] args,
456: String defaultMessage) {
457: return getMessage(code, args, defaultMessage,
458: this .defaultHtmlEscape);
459: }
460:
461: /**
462: * Retrieve the message for the given code, using the "defaultHtmlEscape" setting.
463: * @param code code of the message
464: * @param args arguments for the message as a List, or <code>null</code> if none
465: * @param defaultMessage String to return if the lookup fails
466: * @return the message
467: */
468: public String getMessage(String code, List args,
469: String defaultMessage) {
470: return getMessage(code, (args != null ? args.toArray() : null),
471: defaultMessage, this .defaultHtmlEscape);
472: }
473:
474: /**
475: * Retrieve the message for the given code.
476: * @param code code of the message
477: * @param args arguments for the message, or <code>null</code> if none
478: * @param defaultMessage String to return if the lookup fails
479: * @param htmlEscape HTML escape the message?
480: * @return the message
481: */
482: public String getMessage(String code, Object[] args,
483: String defaultMessage, boolean htmlEscape) {
484: String msg = this .webApplicationContext.getMessage(code, args,
485: defaultMessage, this .locale);
486: return (htmlEscape ? HtmlUtils.htmlEscape(msg) : msg);
487: }
488:
489: /**
490: * Retrieve the message for the given code, using the "defaultHtmlEscape" setting.
491: * @param code code of the message
492: * @return the message
493: * @throws org.springframework.context.NoSuchMessageException if not found
494: */
495: public String getMessage(String code) throws NoSuchMessageException {
496: return getMessage(code, null, this .defaultHtmlEscape);
497: }
498:
499: /**
500: * Retrieve the message for the given code, using the "defaultHtmlEscape" setting.
501: * @param code code of the message
502: * @param args arguments for the message, or <code>null</code> if none
503: * @return the message
504: * @throws org.springframework.context.NoSuchMessageException if not found
505: */
506: public String getMessage(String code, Object[] args)
507: throws NoSuchMessageException {
508: return getMessage(code, args, this .defaultHtmlEscape);
509: }
510:
511: /**
512: * Retrieve the message for the given code, using the "defaultHtmlEscape" setting.
513: * @param code code of the message
514: * @param args arguments for the message as a List, or <code>null</code> if none
515: * @return the message
516: * @throws org.springframework.context.NoSuchMessageException if not found
517: */
518: public String getMessage(String code, List args)
519: throws NoSuchMessageException {
520: return getMessage(code, (args != null ? args.toArray() : null),
521: this .defaultHtmlEscape);
522: }
523:
524: /**
525: * Retrieve the message for the given code.
526: * @param code code of the message
527: * @param args arguments for the message, or <code>null</code> if none
528: * @param htmlEscape HTML escape the message?
529: * @return the message
530: * @throws org.springframework.context.NoSuchMessageException if not found
531: */
532: public String getMessage(String code, Object[] args,
533: boolean htmlEscape) throws NoSuchMessageException {
534: String msg = this .webApplicationContext.getMessage(code, args,
535: this .locale);
536: return (htmlEscape ? HtmlUtils.htmlEscape(msg) : msg);
537: }
538:
539: /**
540: * Retrieve the given MessageSourceResolvable (e.g. an ObjectError instance),
541: * using the "defaultHtmlEscape" setting.
542: * @param resolvable the MessageSourceResolvable
543: * @return the message
544: * @throws org.springframework.context.NoSuchMessageException if not found
545: */
546: public String getMessage(MessageSourceResolvable resolvable)
547: throws NoSuchMessageException {
548: return getMessage(resolvable, this .defaultHtmlEscape);
549: }
550:
551: /**
552: * Retrieve the given MessageSourceResolvable (e.g. an ObjectError instance).
553: * @param resolvable the MessageSourceResolvable
554: * @param htmlEscape HTML escape the message?
555: * @return the message
556: * @throws org.springframework.context.NoSuchMessageException if not found
557: */
558: public String getMessage(MessageSourceResolvable resolvable,
559: boolean htmlEscape) throws NoSuchMessageException {
560: String msg = this .webApplicationContext.getMessage(resolvable,
561: this .locale);
562: return (htmlEscape ? HtmlUtils.htmlEscape(msg) : msg);
563: }
564:
565: /**
566: * Retrieve the theme message for the given code.
567: * <p>Note that theme messages are never HTML-escaped, as they typically
568: * denote theme-specific resource paths and not client-visible messages.
569: * @param code code of the message
570: * @param defaultMessage String to return if the lookup fails
571: * @return the message
572: */
573: public String getThemeMessage(String code, String defaultMessage) {
574: return this .theme.getMessageSource().getMessage(code, null,
575: defaultMessage, this .locale);
576: }
577:
578: /**
579: * Retrieve the theme message for the given code.
580: * <p>Note that theme messages are never HTML-escaped, as they typically
581: * denote theme-specific resource paths and not client-visible messages.
582: * @param code code of the message
583: * @param args arguments for the message, or <code>null</code> if none
584: * @param defaultMessage String to return if the lookup fails
585: * @return the message
586: */
587: public String getThemeMessage(String code, Object[] args,
588: String defaultMessage) {
589: return this .theme.getMessageSource().getMessage(code, args,
590: defaultMessage, this .locale);
591: }
592:
593: /**
594: * Retrieve the theme message for the given code.
595: * <p>Note that theme messages are never HTML-escaped, as they typically
596: * denote theme-specific resource paths and not client-visible messages.
597: * @param code code of the message
598: * @param args arguments for the message as a List, or <code>null</code> if none
599: * @param defaultMessage String to return if the lookup fails
600: * @return the message
601: */
602: public String getThemeMessage(String code, List args,
603: String defaultMessage) {
604: return this .theme.getMessageSource().getMessage(code,
605: (args != null ? args.toArray() : null), defaultMessage,
606: this .locale);
607: }
608:
609: /**
610: * Retrieve the theme message for the given code.
611: * <p>Note that theme messages are never HTML-escaped, as they typically
612: * denote theme-specific resource paths and not client-visible messages.
613: * @param code code of the message
614: * @return the message
615: * @throws org.springframework.context.NoSuchMessageException if not found
616: */
617: public String getThemeMessage(String code)
618: throws NoSuchMessageException {
619: return this .theme.getMessageSource().getMessage(code, null,
620: this .locale);
621: }
622:
623: /**
624: * Retrieve the theme message for the given code.
625: * <p>Note that theme messages are never HTML-escaped, as they typically
626: * denote theme-specific resource paths and not client-visible messages.
627: * @param code code of the message
628: * @param args arguments for the message, or <code>null</code> if none
629: * @return the message
630: * @throws org.springframework.context.NoSuchMessageException if not found
631: */
632: public String getThemeMessage(String code, Object[] args)
633: throws NoSuchMessageException {
634: return this .theme.getMessageSource().getMessage(code, args,
635: this .locale);
636: }
637:
638: /**
639: * Retrieve the theme message for the given code.
640: * <p>Note that theme messages are never HTML-escaped, as they typically
641: * denote theme-specific resource paths and not client-visible messages.
642: * @param code code of the message
643: * @param args arguments for the message as a List, or <code>null</code> if none
644: * @return the message
645: * @throws org.springframework.context.NoSuchMessageException if not found
646: */
647: public String getThemeMessage(String code, List args)
648: throws NoSuchMessageException {
649: return this .theme.getMessageSource().getMessage(code,
650: (args != null ? args.toArray() : null), this .locale);
651: }
652:
653: /**
654: * Retrieve the given MessageSourceResolvable in the current theme.
655: * <p>Note that theme messages are never HTML-escaped, as they typically
656: * denote theme-specific resource paths and not client-visible messages.
657: * @param resolvable the MessageSourceResolvable
658: * @return the message
659: * @throws org.springframework.context.NoSuchMessageException if not found
660: */
661: public String getThemeMessage(MessageSourceResolvable resolvable)
662: throws NoSuchMessageException {
663: return this .theme.getMessageSource().getMessage(resolvable,
664: this .locale);
665: }
666:
667: /**
668: * Retrieve the Errors instance for the given bind object,
669: * using the "defaultHtmlEscape" setting.
670: * @param name name of the bind object
671: * @return the Errors instance, or <code>null</code> if not found
672: */
673: public Errors getErrors(String name) {
674: return getErrors(name, this .defaultHtmlEscape);
675: }
676:
677: /**
678: * Retrieve the Errors instance for the given bind object.
679: * @param name name of the bind object
680: * @param htmlEscape create an Errors instance with automatic HTML escaping?
681: * @return the Errors instance, or <code>null</code> if not found
682: */
683: public Errors getErrors(String name, boolean htmlEscape) {
684: if (this .errorsMap == null) {
685: this .errorsMap = new HashMap();
686: }
687: Errors errors = (Errors) this .errorsMap.get(name);
688: boolean put = false;
689: if (errors == null) {
690: errors = (Errors) getModelObject(BindingResult.MODEL_KEY_PREFIX
691: + name);
692: // Check old BindException prefix for backwards compatibility.
693: if (errors == null) {
694: errors = (Errors) getModelObject(BindException.ERROR_KEY_PREFIX
695: + name);
696: }
697: if (errors == null) {
698: return null;
699: }
700: put = true;
701: }
702: if (htmlEscape && !(errors instanceof EscapedErrors)) {
703: errors = new EscapedErrors(errors);
704: put = true;
705: } else if (!htmlEscape && errors instanceof EscapedErrors) {
706: errors = ((EscapedErrors) errors).getSource();
707: put = true;
708: }
709: if (put) {
710: this .errorsMap.put(name, errors);
711: }
712: return errors;
713: }
714:
715: /**
716: * Retrieve the model object for the given model name,
717: * either from the model or from the request attributes.
718: * @param modelName the name of the model object
719: * @return the model object
720: */
721: protected Object getModelObject(String modelName) {
722: if (this .model != null) {
723: return this .model.get(modelName);
724: } else {
725: return this .request.getAttribute(modelName);
726: }
727: }
728:
729: /**
730: * Create a BindStatus for the given bind object,
731: * using the "defaultHtmlEscape" setting.
732: * @param path the bean and property path for which values and errors
733: * will be resolved (e.g. "person.age")
734: * @return the new BindStatus instance
735: * @throws IllegalStateException if no corresponding Errors object found
736: */
737: public BindStatus getBindStatus(String path)
738: throws IllegalStateException {
739: return new BindStatus(this , path, this .defaultHtmlEscape);
740: }
741:
742: /**
743: * Create a BindStatus for the given bind object,
744: * using the "defaultHtmlEscape" setting.
745: * @param path the bean and property path for which values and errors
746: * will be resolved (e.g. "person.age")
747: * @param htmlEscape create a BindStatus with automatic HTML escaping?
748: * @return the new BindStatus instance
749: * @throws IllegalStateException if no corresponding Errors object found
750: */
751: public BindStatus getBindStatus(String path, boolean htmlEscape)
752: throws IllegalStateException {
753: return new BindStatus(this, path, htmlEscape);
754: }
755:
756: }
|