KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > view > velocity > VelocityView


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.web.servlet.view.velocity;
18
19 import java.util.Enumeration JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.Locale JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Properties JavaDoc;
25
26 import javax.servlet.http.HttpServletRequest JavaDoc;
27 import javax.servlet.http.HttpServletResponse JavaDoc;
28
29 import org.apache.velocity.Template;
30 import org.apache.velocity.VelocityContext;
31 import org.apache.velocity.app.VelocityEngine;
32 import org.apache.velocity.app.tools.VelocityFormatter;
33 import org.apache.velocity.context.Context;
34 import org.apache.velocity.exception.MethodInvocationException;
35 import org.apache.velocity.exception.ResourceNotFoundException;
36 import org.apache.velocity.tools.generic.DateTool;
37 import org.apache.velocity.tools.generic.NumberTool;
38
39 import org.springframework.beans.BeansException;
40 import org.springframework.beans.factory.BeanFactoryUtils;
41 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
42 import org.springframework.context.ApplicationContextException;
43 import org.springframework.util.ClassUtils;
44 import org.springframework.web.servlet.support.RequestContextUtils;
45 import org.springframework.web.servlet.view.AbstractTemplateView;
46 import org.springframework.web.util.NestedServletException;
47
48 /**
49  * View using the Velocity template engine.
50  *
51  * <p>Exposes the following JavaBean properties:
52  * <ul>
53  * <li><b>url</b>: the location of the Velocity template to be wrapped,
54  * relative to the Velocity resource loader path (see VelocityConfigurer).
55  * <li><b>encoding</b> (optional, default is determined by Velocity configuration):
56  * the encoding of the Velocity template file
57  * <li><b>velocityFormatterAttribute</b> (optional, default=null): the name of
58  * the VelocityFormatter helper object to expose in the Velocity context of this
59  * view, or <code>null</code> if not needed. VelocityFormatter is part of standard Velocity.
60  * <li><b>dateToolAttribute</b> (optional, default=null): the name of the
61  * DateTool helper object to expose in the Velocity context of this view,
62  * or <code>null</code> if not needed. DateTool is part of Velocity Tools 1.0.
63  * <li><b>numberToolAttribute</b> (optional, default=null): the name of the
64  * NumberTool helper object to expose in the Velocity context of this view,
65  * or <code>null</code> if not needed. NumberTool is part of Velocity Tools 1.1.
66  * <li><b>cacheTemplate</b> (optional, default=false): whether or not the Velocity
67  * template should be cached. It should normally be true in production, but setting
68  * this to false enables us to modify Velocity templates without restarting the
69  * application (similar to JSPs). Note that this is a minor optimization only,
70  * as Velocity itself caches templates in a modification-aware fashion.
71  * </ul>
72  *
73  * <p>Depends on a VelocityConfig object such as VelocityConfigurer being
74  * accessible in the current web application context, with any bean name.
75  * Alternatively, you can set the VelocityEngine object as bean property.
76  *
77  * <p>Note: Spring's VelocityView requires Velocity 1.3 or higher, and optionally
78  * Velocity Tools 1.0 or higher (depending on the use of DateTool and/or NumberTool).
79  *
80  * @author Rod Johnson
81  * @author Juergen Hoeller
82  * @see VelocityConfig
83  * @see VelocityConfigurer
84  * @see #setUrl
85  * @see #setExposeSpringMacroHelpers
86  * @see #setEncoding
87  * @see #setVelocityEngine
88  * @see VelocityConfig
89  * @see VelocityConfigurer
90  */

91 public class VelocityView extends AbstractTemplateView {
92
93     private Map JavaDoc toolAttributes;
94
95     private String JavaDoc velocityFormatterAttribute;
96
97     private String JavaDoc dateToolAttribute;
98
99     private String JavaDoc numberToolAttribute;
100
101     private String JavaDoc encoding;
102
103     private boolean cacheTemplate = false;
104
105     private VelocityEngine velocityEngine;
106
107     private Template template;
108
109
110     /**
111      * Set tool attributes to expose to the view, as attribute name / class name pairs.
112      * An instance of the given class will be added to the Velocity context for each
113      * rendering operation, under the given attribute name.
114      * <p>For example, an instance of MathTool, which is part of the generic package
115      * of Velocity Tools, can be bound under the attribute name "math", specifying the
116      * fully qualified class name "org.apache.velocity.tools.generic.MathTool" as value.
117      * <p>Note that VelocityView can only create simple generic tools or values, that is,
118      * classes with a public default constructor and no further initialization needs.
119      * This class does not do any further checks, to not introduce a required dependency
120      * on a specific tools package.
121      * <p>For tools that are part of the view package of Velocity Tools, a special
122      * Velocity context and a special init callback are needed. Use VelocityToolboxView
123      * in such a case, or override <code>createVelocityContext</code> and
124      * <code>initTool</code> accordingly.
125      * <p>For a simple VelocityFormatter instance or special locale-aware instances
126      * of DateTool/NumberTool, which are part of the generic package of Velocity Tools,
127      * specify the "velocityFormatterAttribute", "dateToolAttribute" or
128      * "numberToolAttribute" properties, respectively.
129      * @param toolAttributes attribute names as keys, and tool class names as values
130      * @see org.apache.velocity.tools.generic.MathTool
131      * @see VelocityToolboxView
132      * @see #createVelocityContext
133      * @see #initTool
134      * @see #setVelocityFormatterAttribute
135      * @see #setDateToolAttribute
136      * @see #setNumberToolAttribute
137      */

138     public void setToolAttributes(Properties JavaDoc toolAttributes) {
139         this.toolAttributes = new HashMap JavaDoc(toolAttributes.size());
140         for (Enumeration JavaDoc attributeNames = toolAttributes.propertyNames(); attributeNames.hasMoreElements();) {
141             String JavaDoc attributeName = (String JavaDoc) attributeNames.nextElement();
142             String JavaDoc className = toolAttributes.getProperty(attributeName);
143             Class JavaDoc toolClass = null;
144             try {
145                 toolClass = ClassUtils.forName(className);
146             }
147             catch (ClassNotFoundException JavaDoc ex) {
148                 throw new IllegalArgumentException JavaDoc(
149                         "Invalid definition for tool '" + attributeName + "' - tool class not found: " + ex.getMessage());
150             }
151             this.toolAttributes.put(attributeName, toolClass);
152         }
153     }
154
155     /**
156      * Set the name of the VelocityFormatter helper object to expose in the
157      * Velocity context of this view, or <code>null</code> if not needed.
158      * <p>VelocityFormatter is part of the standard Velocity distribution.
159      * @see org.apache.velocity.app.tools.VelocityFormatter
160      */

161     public void setVelocityFormatterAttribute(String JavaDoc velocityFormatterAttribute) {
162         this.velocityFormatterAttribute = velocityFormatterAttribute;
163     }
164
165     /**
166      * Set the name of the DateTool helper object to expose in the Velocity context
167      * of this view, or <code>null</code> if not needed. The exposed DateTool will be aware of
168      * the current locale, as determined by Spring's LocaleResolver.
169      * <p>DateTool is part of the generic package of Velocity Tools 1.0.
170      * Spring uses a special locale-aware subclass of DateTool.
171      * @see org.apache.velocity.tools.generic.DateTool
172      * @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
173      * @see org.springframework.web.servlet.LocaleResolver
174      */

175     public void setDateToolAttribute(String JavaDoc dateToolAttribute) {
176         this.dateToolAttribute = dateToolAttribute;
177     }
178
179     /**
180      * Set the name of the NumberTool helper object to expose in the Velocity context
181      * of this view, or <code>null</code> if not needed. The exposed NumberTool will be aware of
182      * the current locale, as determined by Spring's LocaleResolver.
183      * <p>NumberTool is part of the generic package of Velocity Tools 1.1.
184      * Spring uses a special locale-aware subclass of NumberTool.
185      * @see org.apache.velocity.tools.generic.NumberTool
186      * @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
187      * @see org.springframework.web.servlet.LocaleResolver
188      */

189     public void setNumberToolAttribute(String JavaDoc numberToolAttribute) {
190         this.numberToolAttribute = numberToolAttribute;
191     }
192
193     /**
194      * Set the encoding of the Velocity template file. Default is determined
195      * by the VelocityEngine: "ISO-8859-1" if not specified otherwise.
196      * <p>Specify the encoding in the VelocityEngine rather than per template
197      * if all your templates share a common encoding.
198      */

199     public void setEncoding(String JavaDoc encoding) {
200         this.encoding = encoding;
201     }
202
203     /**
204      * Return the encoding for the Velocity template.
205      */

206     protected String JavaDoc getEncoding() {
207         return this.encoding;
208     }
209
210     /**
211      * Set whether the Velocity template should be cached. Default is "false".
212      * It should normally be true in production, but setting this to false enables us to
213      * modify Velocity templates without restarting the application (similar to JSPs).
214      * <p>Note that this is a minor optimization only, as Velocity itself caches
215      * templates in a modification-aware fashion.
216      */

217     public void setCacheTemplate(boolean cacheTemplate) {
218         this.cacheTemplate = cacheTemplate;
219     }
220
221     /**
222      * Return whether the Velocity template should be cached.
223      */

224     protected boolean isCacheTemplate() {
225         return this.cacheTemplate;
226     }
227
228     /**
229      * Set the VelocityEngine to be used by this view.
230      * If this is not set, the default lookup will occur: A single VelocityConfig
231      * is expected in the current web application context, with any bean name.
232      * @see VelocityConfig
233      */

234     public void setVelocityEngine(VelocityEngine velocityEngine) {
235         this.velocityEngine = velocityEngine;
236     }
237
238     /**
239      * Return the VelocityEngine used by this view.
240      */

241     protected VelocityEngine getVelocityEngine() {
242         return this.velocityEngine;
243     }
244
245
246     /**
247      * Invoked on startup. Looks for a single VelocityConfig bean to
248      * find the relevant VelocityEngine for this factory.
249      */

250     protected void initApplicationContext() throws BeansException {
251         super.initApplicationContext();
252
253         if (getVelocityEngine() == null) {
254             // No explicit VelocityEngine: try to autodetect one.
255
setVelocityEngine(autodetectVelocityEngine());
256         }
257
258         checkTemplate();
259     }
260
261     /**
262      * Autodetect a VelocityEngine via the ApplicationContext.
263      * Called if no explicit VelocityEngine has been specified.
264      * @return the VelocityEngine to use for VelocityViews
265      * @throws BeansException if no VelocityEngine could be found
266      * @see #getApplicationContext
267      * @see #setVelocityEngine
268      */

269     protected VelocityEngine autodetectVelocityEngine() throws BeansException {
270         try {
271             VelocityConfig velocityConfig = (VelocityConfig)
272                     BeanFactoryUtils.beanOfTypeIncludingAncestors(
273                             getApplicationContext(), VelocityConfig.class, true, false);
274             return velocityConfig.getVelocityEngine();
275         }
276         catch (NoSuchBeanDefinitionException ex) {
277             throw new ApplicationContextException(
278                     "Must define a single VelocityConfig bean in this web application context " +
279                     "(may be inherited): VelocityConfigurer is the usual implementation. " +
280                     "This bean may be given any name.", ex);
281         }
282     }
283
284     /**
285      * Check that the Velocity template used for this view exists and is valid.
286      * <p>Can be overridden to customize the behavior, for example in case of
287      * multiple templates to be rendered into a single view.
288      * @throws ApplicationContextException if the template cannot be found or is invalid
289      */

290     protected void checkTemplate() throws ApplicationContextException {
291         try {
292             // Check that we can get the template, even if we might subsequently get it again.
293
this.template = getTemplate();
294         }
295         catch (ResourceNotFoundException ex) {
296             throw new ApplicationContextException("Cannot find Velocity template for URL [" + getUrl() +
297                 "]: Did you specify the correct resource loader path?", ex);
298         }
299         catch (Exception JavaDoc ex) {
300             throw new ApplicationContextException(
301                     "Could not load Velocity template for URL [" + getUrl() + "]", ex);
302         }
303     }
304
305
306     /**
307      * Process the model map by merging it with the Velocity template.
308      * Output is directed to the servlet response.
309      * <p>This method can be overridden if custom behavior is needed.
310      */

311     protected void renderMergedTemplateModel(
312             Map JavaDoc model, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
313
314         exposeHelpers(model, request);
315
316         Context velocityContext = createVelocityContext(model, request, response);
317         exposeHelpers(velocityContext, request, response);
318         exposeToolAttributes(velocityContext, request);
319
320         doRender(velocityContext, response);
321     }
322
323     /**
324      * Expose helpers unique to each rendering operation. This is necessary so that
325      * different rendering operations can't overwrite each other's formats etc.
326      * <p>Called by <code>renderMergedTemplateModel</code>. The default implementation
327      * is empty. This method can be overridden to add custom helpers to the model.
328      * @param model the model that will be passed to the template for merging
329      * @param request current HTTP request
330      * @throws Exception if there's a fatal error while we're adding model attributes
331      * @see #renderMergedTemplateModel
332      */

333     protected void exposeHelpers(Map JavaDoc model, HttpServletRequest JavaDoc request) throws Exception JavaDoc {
334     }
335
336     /**
337      * Create a Velocity Context instance for the given model,
338      * to be passed to the template for merging.
339      * <p>The default implementation delegates to {@link #createVelocityContext(Map)}.
340      * Can be overridden for a special context class, for example ChainedContext which
341      * is part of the view package of Velocity Tools. ChainedContext is needed for
342      * initialization of ViewTool instances.
343      * <p>Have a look at {@link VelocityToolboxView}, which pre-implements
344      * ChainedContext support. This is not part of the standard VelocityView class
345      * in order to avoid a required dependency on the view package of Velocity Tools.
346      * @param model the model Map, containing the model attributes to be exposed to the view
347      * @param request current HTTP request
348      * @param response current HTTP response
349      * @return the Velocity Context
350      * @throws Exception if there's a fatal error while creating the context
351      * @see #createVelocityContext(Map)
352      * @see #initTool
353      * @see org.apache.velocity.tools.view.context.ChainedContext
354      * @see VelocityToolboxView
355      */

356     protected Context createVelocityContext(
357             Map JavaDoc model, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
358
359         return createVelocityContext(model);
360     }
361
362     /**
363      * Create a Velocity Context instance for the given model,
364      * to be passed to the template for merging.
365      * <p>Default implementation creates an instance of Velocity's
366      * VelocityContext implementation class.
367      * @param model the model Map, containing the model attributes
368      * to be exposed to the view
369      * @return the Velocity Context
370      * @throws Exception if there's a fatal error while creating the context
371      * @see org.apache.velocity.VelocityContext
372      */

373     protected Context createVelocityContext(Map JavaDoc model) throws Exception JavaDoc {
374         return new VelocityContext(model);
375     }
376
377     /**
378      * Expose helpers unique to each rendering operation. This is necessary so that
379      * different rendering operations can't overwrite each other's formats etc.
380      * <p>Called by <code>renderMergedTemplateModel</code>. Default implementation
381      * delegates to <code>exposeHelpers(velocityContext, request)</code>. This method
382      * can be overridden to add special tools to the context, needing the servlet response
383      * to initialize (see Velocity Tools, for example LinkTool and ViewTool/ChainedContext).
384      * @param velocityContext Velocity context that will be passed to the template
385      * @param request current HTTP request
386      * @param response current HTTP response
387      * @throws Exception if there's a fatal error while we're adding model attributes
388      * @see #exposeHelpers(org.apache.velocity.context.Context, HttpServletRequest)
389      */

390     protected void exposeHelpers(
391             Context velocityContext, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
392
393         exposeHelpers(velocityContext, request);
394     }
395
396     /**
397      * Expose helpers unique to each rendering operation. This is necessary so that
398      * different rendering operations can't overwrite each other's formats etc.
399      * <p>Default implementation is empty. This method can be overridden to add
400      * custom helpers to the Velocity context.
401      * @param velocityContext Velocity context that will be passed to the template
402      * @param request current HTTP request
403      * @throws Exception if there's a fatal error while we're adding model attributes
404      * @see #exposeHelpers(Map, HttpServletRequest)
405      */

406     protected void exposeHelpers(Context velocityContext, HttpServletRequest JavaDoc request) throws Exception JavaDoc {
407     }
408
409     /**
410      * Expose the tool attributes, according to corresponding bean property settings.
411      * <p>Do not override this method unless for further tools driven by bean properties.
412      * Override one of the <code>exposeHelpers</code> methods to add custom helpers.
413      * @param velocityContext Velocity context that will be passed to the template
414      * @param request current HTTP request
415      * @throws Exception if there's a fatal error while we're adding model attributes
416      * @see #setVelocityFormatterAttribute
417      * @see #setDateToolAttribute
418      * @see #setNumberToolAttribute
419      * @see #exposeHelpers(Map, HttpServletRequest)
420      * @see #exposeHelpers(org.apache.velocity.context.Context, HttpServletRequest, HttpServletResponse)
421      */

422     protected void exposeToolAttributes(Context velocityContext, HttpServletRequest JavaDoc request) throws Exception JavaDoc {
423         // Expose generic attributes.
424
if (this.toolAttributes != null) {
425             for (Iterator JavaDoc it = this.toolAttributes.entrySet().iterator(); it.hasNext();) {
426                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
427                 String JavaDoc attributeName = (String JavaDoc) entry.getKey();
428                 Class JavaDoc toolClass = (Class JavaDoc) entry.getValue();
429                 try {
430                     Object JavaDoc tool = toolClass.newInstance();
431                     initTool(tool, velocityContext);
432                     velocityContext.put(attributeName, tool);
433                 }
434                 catch (Exception JavaDoc ex) {
435                     throw new NestedServletException("Could not instantiate Velocity tool '" + attributeName + "'", ex);
436                 }
437             }
438         }
439
440         // Expose VelocityFormatter attribute.
441
if (this.velocityFormatterAttribute != null) {
442             velocityContext.put(this.velocityFormatterAttribute, new VelocityFormatter(velocityContext));
443         }
444
445         // Expose locale-aware DateTool/NumberTool attributes.
446
if (this.dateToolAttribute != null || this.numberToolAttribute != null) {
447             Locale JavaDoc locale = RequestContextUtils.getLocale(request);
448             if (this.dateToolAttribute != null) {
449                 velocityContext.put(this.dateToolAttribute, new LocaleAwareDateTool(locale));
450             }
451             if (this.numberToolAttribute != null) {
452                 velocityContext.put(this.numberToolAttribute, new LocaleAwareNumberTool(locale));
453             }
454         }
455     }
456
457     /**
458      * Initialize the given tool instance. The default implementation is empty.
459      * <p>Can be overridden to check for special callback interfaces, for example
460      * the ViewContext interface which is part of the view package of Velocity Tools.
461      * In the particular case of ViewContext, you'll usually also need a special
462      * Velocity context, like ChainedContext which is part of Velocity Tools too.
463      * <p>Have a look at {@link VelocityToolboxView}, which pre-implements such a
464      * ViewTool check. This is not part of the standard VelocityView class in order
465      * to avoid a required dependency on the view package of Velocity Tools.
466      * @param tool the tool instance to initialize
467      * @param velocityContext the Velocity context
468      * @throws Exception if initializion of the tool failed
469      * @see #createVelocityContext
470      * @see org.apache.velocity.tools.view.context.ViewContext
471      * @see org.apache.velocity.tools.view.context.ChainedContext
472      * @see VelocityToolboxView
473      */

474     protected void initTool(Object JavaDoc tool, Context velocityContext) throws Exception JavaDoc {
475     }
476
477
478     /**
479      * Render the Velocity view to the given response, using the given Velocity
480      * context which contains the complete template model to use.
481      * <p>The default implementation renders the template specified by the "url"
482      * bean property, retrieved via <code>getTemplate</code>. It delegates to the
483      * <code>mergeTemplate</code> method to merge the template instance with the
484      * given Velocity context.
485      * <p>Can be overridden to customize the behavior, for example to render
486      * multiple templates into a single view.
487      * @param context the Velocity context to use for rendering
488      * @param response servlet response (use this to get the OutputStream or Writer)
489      * @throws Exception if thrown by Velocity
490      * @see #setUrl
491      * @see #getTemplate()
492      * @see #mergeTemplate
493      */

494     protected void doRender(Context context, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
495         if (logger.isDebugEnabled()) {
496             logger.debug("Rendering Velocity template [" + getUrl() + "] in VelocityView '" + getBeanName() + "'");
497         }
498         mergeTemplate(getTemplate(), context, response);
499     }
500
501     /**
502      * Retrieve the Velocity template to be rendered by this view.
503      * <p>By default, the template specified by the "url" bean property will be
504      * retrieved: either returning a cached template instance or loading a fresh
505      * instance (according to the "cacheTemplate" bean property)
506      * @return the Velocity template to render
507      * @throws Exception if thrown by Velocity
508      * @see #setUrl
509      * @see #setCacheTemplate
510      * @see #getTemplate(String)
511      */

512     protected Template getTemplate() throws Exception JavaDoc {
513         // We already hold a reference to the template, but we might want to load it
514
// if not caching. Velocity itself caches templates, so our ability to
515
// cache templates in this class is a minor optimization only.
516
if (isCacheTemplate() && this.template != null) {
517             return this.template;
518         }
519         else {
520             return getTemplate(getUrl());
521         }
522     }
523
524     /**
525      * Retrieve the Velocity template specified by the given name,
526      * using the encoding specified by the "encoding" bean property.
527      * <p>Can be called by subclasses to retrieve a specific template,
528      * for example to render multiple templates into a single view.
529      * @param name the file name of the desired template
530      * @return the Velocity template
531      * @throws Exception if thrown by Velocity
532      * @see org.apache.velocity.app.VelocityEngine#getTemplate
533      */

534     protected Template getTemplate(String JavaDoc name) throws Exception JavaDoc {
535         return (getEncoding() != null ?
536                 getVelocityEngine().getTemplate(name, getEncoding()) :
537                 getVelocityEngine().getTemplate(name));
538     }
539
540     /**
541      * Merge the template with the context.
542      * Can be overridden to customize the behavior.
543      * @param template the template to merge
544      * @param context the Velocity context to use for rendering
545      * @param response servlet response (use this to get the OutputStream or Writer)
546      * @throws Exception if thrown by Velocity
547      * @see org.apache.velocity.Template#merge
548      */

549     protected void mergeTemplate(
550             Template template, Context context, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
551
552         try {
553             template.merge(context, response.getWriter());
554         }
555         catch (MethodInvocationException ex) {
556             throw new NestedServletException(
557                     "Method invocation failed during rendering of Velocity view with name '" +
558                     getBeanName() + "': " + ex.getMessage() + "; reference [" + ex.getReferenceName() +
559                     "], method '" + ex.getMethodName() + "'",
560                     ex.getWrappedThrowable());
561         }
562     }
563
564
565     /**
566      * Subclass of DateTool from Velocity Tools, using a passed-in Locale
567      * (usually the RequestContext Locale) instead of the default Locale.N
568      * @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
569      */

570     private static class LocaleAwareDateTool extends DateTool {
571
572         private final Locale JavaDoc locale;
573
574         private LocaleAwareDateTool(Locale JavaDoc locale) {
575             this.locale = locale;
576         }
577
578         public Locale JavaDoc getLocale() {
579             return this.locale;
580         }
581     }
582
583
584     /**
585      * Subclass of NumberTool from Velocity Tools, using a passed-in Locale
586      * (usually the RequestContext Locale) instead of the default Locale.
587      * @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
588      */

589     private static class LocaleAwareNumberTool extends NumberTool {
590
591         private final Locale JavaDoc locale;
592
593         private LocaleAwareNumberTool(Locale JavaDoc locale) {
594             this.locale = locale;
595         }
596
597         public Locale JavaDoc getLocale() {
598             return this.locale;
599         }
600     }
601
602 }
603
Popular Tags