KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > view > ResourceBundleViewResolver


1 /*
2  * Copyright 2002-2006 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;
18
19 import java.util.HashMap JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.LinkedList JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Locale JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.MissingResourceException JavaDoc;
26 import java.util.ResourceBundle JavaDoc;
27
28 import org.springframework.beans.BeansException;
29 import org.springframework.beans.factory.BeanFactory;
30 import org.springframework.beans.factory.DisposableBean;
31 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
32 import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
33 import org.springframework.context.ConfigurableApplicationContext;
34 import org.springframework.core.Ordered;
35 import org.springframework.web.context.support.GenericWebApplicationContext;
36 import org.springframework.web.servlet.View;
37
38 /**
39  * {@link org.springframework.web.servlet.ViewResolver} implementation
40  * that uses bean definitions in a {@link ResourceBundle}, specified by
41  * the bundle basename.
42  *
43  * <p>The bundle is typically defined in a properties file, located in
44  * the class path. The default bundle basename is "views".
45  *
46  * <p>This <code>ViewResolver</code> supports localized view definitions,
47  * using the default support of {@link java.util.PropertyResourceBundle}.
48  * For example, the basename "views" will be resolved as class path resources
49  * "views_de_AT.properties", "views_de.properties", "views.properties" -
50  * for a given Locale "de_AT".
51  *
52  * <p>Note: this <code>ViewResolver</code> implements the {@link Ordered}
53  * interface to allow for flexible participation in <code>ViewResolver</code>
54  * chaining. For example, some special views could be defined via this
55  * <code>ViewResolver</code> (giving it 0 as "order" value), while all
56  * remaining views could be resolved by a {@link UrlBasedViewResolver}.
57  *
58  * @author Rod Johnson
59  * @author Juergen Hoeller
60  * @see java.util.ResourceBundle#getBundle
61  * @see java.util.PropertyResourceBundle
62  * @see UrlBasedViewResolver
63  */

64 public class ResourceBundleViewResolver extends AbstractCachingViewResolver implements Ordered, DisposableBean {
65
66     /** The default basename if no other basename is supplied. */
67     public final static String JavaDoc DEFAULT_BASENAME = "views";
68
69
70     private int order = Integer.MAX_VALUE; // default: same as non-Ordered
71

72     private String JavaDoc[] basenames = new String JavaDoc[] {DEFAULT_BASENAME};
73
74     private ClassLoader JavaDoc bundleClassLoader = Thread.currentThread().getContextClassLoader();
75
76     private String JavaDoc defaultParentView;
77
78     /* Locale -> BeanFactory */
79     private final Map JavaDoc localeCache = new HashMap JavaDoc();
80
81     /* List of ResourceBundle -> BeanFactory */
82     private final Map JavaDoc bundleCache = new HashMap JavaDoc();
83
84
85     public void setOrder(int order) {
86         this.order = order;
87     }
88
89     public int getOrder() {
90         return order;
91     }
92
93     /**
94      * Set the basename, as defined in the {@link java.util.ResourceBundle}
95      * documentation.
96      * <p><code>ResourceBundle</code> supports different suffixes. For example,
97      * a base name of "views" might map to <code>ResourceBundle</code> files
98      * "views", "views_en_au" and "views_de".
99      * <p>The default is "views".
100      * @param basename the <code>ResourceBundle</code> basename
101      * @see #setBasenames
102      * @see java.util.ResourceBundle
103      */

104     public void setBasename(String JavaDoc basename) {
105         setBasenames(new String JavaDoc[] {basename});
106     }
107
108     /**
109      * Set multiple <code>ResourceBundle</code> basenames.
110      * @param basenames multiple <code>ResourceBundle</code> basenames
111      * @see #setBasename
112      */

113     public void setBasenames(String JavaDoc[] basenames) {
114         this.basenames = basenames;
115     }
116
117     /**
118      * Set the {@link ClassLoader} to load resource bundles with.
119      * Default is the thread context <code>ClassLoader</code>.
120      * @param classLoader the <code>ClassLoader</code> to load resource bundles with
121      */

122     public void setBundleClassLoader(ClassLoader JavaDoc classLoader) {
123         this.bundleClassLoader = classLoader;
124     }
125
126     /**
127      * Return the {@link ClassLoader} to load resource bundles with.
128      * <p>Default is the specified bundle <code>ClassLoader</code>,
129      * usually the thread context <code>ClassLoader</code>.
130      * @return the <code>ClassLoader</code> to load resource bundles with
131      */

132     protected ClassLoader JavaDoc getBundleClassLoader() {
133         return bundleClassLoader;
134     }
135
136     /**
137      * Set the default parent for views defined in the <code>ResourceBundle</code>.
138      * <p>This avoids repeated "yyy1.(parent)=xxx", "yyy2.(parent)=xxx" definitions
139      * in the bundle, especially if all defined views share the same parent.
140      * <p>The parent will typically define the view class and common attributes.
141      * Concrete views might simply consist of an URL definition then:
142      * a la "yyy1.url=/my.jsp", "yyy2.url=/your.jsp".
143      * <p>View definitions that define their own parent or carry their own
144      * class can still override this. Strictly speaking, the rule that a
145      * default parent setting does not apply to a bean definition that
146      * carries a class is there for backwards compatiblity reasons.
147      * It still matches the typical use case.
148      * @param defaultParentView the default parent view
149      */

150     public void setDefaultParentView(String JavaDoc defaultParentView) {
151         this.defaultParentView = defaultParentView;
152     }
153
154
155     protected View loadView(String JavaDoc viewName, Locale JavaDoc locale) throws Exception JavaDoc {
156         BeanFactory factory = initFactory(locale);
157         try {
158             return (View) factory.getBean(viewName, View.class);
159         }
160         catch (NoSuchBeanDefinitionException ex) {
161             // to allow for ViewResolver chaining
162
return null;
163         }
164     }
165
166     /**
167      * Initialize the {@link BeanFactory} from the <code>ResourceBundle</code>,
168      * for the given {@link Locale locale}.
169      * <p>Synchronized because of access by parallel threads.
170      * @param locale the target <code>Locale</code>
171      */

172     protected synchronized BeanFactory initFactory(Locale JavaDoc locale) throws Exception JavaDoc {
173         // Try to find cached factory for Locale:
174
// Have we already encountered that Locale before?
175
if (isCache()) {
176             BeanFactory cachedFactory = (BeanFactory) this.localeCache.get(locale);
177             if (cachedFactory != null) {
178                 return cachedFactory;
179             }
180         }
181
182         // Build list of ResourceBundle references for Locale.
183
List JavaDoc bundles = new LinkedList JavaDoc();
184         for (int i = 0; i < this.basenames.length; i++) {
185             ResourceBundle JavaDoc bundle = getBundle(this.basenames[i], locale);
186             bundles.add(bundle);
187         }
188
189         // Try to find cached factory for ResourceBundle list:
190
// even if Locale was different, same bundles might have been found.
191
if (isCache()) {
192             BeanFactory cachedFactory = (BeanFactory) this.bundleCache.get(bundles);
193             if (cachedFactory != null) {
194                 this.localeCache.put(locale, cachedFactory);
195                 return cachedFactory;
196             }
197         }
198
199         // Create child ApplicationContext for views.
200
GenericWebApplicationContext factory = new GenericWebApplicationContext();
201         factory.setParent(getApplicationContext());
202         factory.setServletContext(getServletContext());
203
204         // Load bean definitions from resource bundle.
205
PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(factory);
206         reader.setDefaultParentBean(this.defaultParentView);
207         for (int i = 0; i < bundles.size(); i++) {
208             ResourceBundle JavaDoc bundle = (ResourceBundle JavaDoc) bundles.get(i);
209             reader.registerBeanDefinitions(bundle);
210         }
211
212         factory.refresh();
213
214         // Cache factory for both Locale and ResourceBundle list.
215
if (isCache()) {
216             this.localeCache.put(locale, factory);
217             this.bundleCache.put(bundles, factory);
218         }
219
220         return factory;
221     }
222
223     /**
224      * Obtain the resource bundle for the given basename and {@link Locale}.
225      * @param basename the basename to look for
226      * @param locale the <code>Locale</code> to look for
227      * @return the corresponding <code>ResourceBundle</code>
228      * @throws MissingResourceException if no matching bundle could be found
229      * @see java.util.ResourceBundle#getBundle(String, java.util.Locale, ClassLoader)
230      */

231     protected ResourceBundle JavaDoc getBundle(String JavaDoc basename, Locale JavaDoc locale) throws MissingResourceException JavaDoc {
232         return ResourceBundle.getBundle(basename, locale, getBundleClassLoader());
233     }
234
235
236     /**
237      * Close the bundle bean factories on context shutdown.
238      */

239     public void destroy() throws BeansException {
240         for (Iterator JavaDoc it = this.bundleCache.values().iterator(); it.hasNext();) {
241             ConfigurableApplicationContext factory = (ConfigurableApplicationContext) it.next();
242             factory.close();
243         }
244         this.localeCache.clear();
245         this.bundleCache.clear();
246     }
247
248 }
249
Popular Tags