2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shale.util;
19
20 import java.text.MessageFormat;
21 import java.util.HashMap;
22 import java.util.Locale;
23 import java.util.Map;
24 import java.util.MissingResourceException;
25 import java.util.ResourceBundle;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 /***
30 * <p>Utility wrapper around resource bundles that provides locale-specific
31 * message string lookups, as well as parameter replacement services.</p>
32 *
33 * <p>If desired, this class can be used to define a managed bean wrapping
34 * a specified resource bundle, with a declaration like this in a
35 * <code>faces-config.xml</code> configuration file:</p>
36 * <pre>
37 * <managed-bean>
38 * <managed-bean-name>messages</managed-bean-name>
39 * <managed-bean-class>
40 * org.apache.shale.util.Messages
41 * </managed-bean-class>
42 * <managed-bean-scope>application</managed-bean-scope>
43 * <managed-property>
44 * <property-name>name</property-name>
45 * <value>com.mycompany.mypackage.Bundle</value>
46 * </managed-property>
47 * </managed-bean>
48 * </pre>
49 *
50 * $Id: Messages.java 481403 2006-12-01 21:27:54Z rahul $
51 */
52 public class Messages {
53
54
55
56
57
58 /***
59 * <p>Construct an initialized {@link Messages} wrapper. At least the
60 * <code>name</code> property must be initialized before the message
61 * retrieval public methods may be successfully utilized.</p>
62 */
63 public Messages() {
64
65 this(null, null);
66
67 }
68
69
70 /***
71 * <p>Construct a new {@link Messages} wrapper around the specified
72 * resource bundle name, loaded by the default class loader.</p>
73 *
74 * @param name Name of the requested <code>ResourceBundle</code>
75 */
76 public Messages(String name) {
77
78 this(name, null);
79
80 }
81
82
83 /***
84 * <P>Construct a new {@link Messages} wrapper around the specified
85 * resource bundle name, loaded by the specified class loader.</p>
86 *
87 * @param name Name of the requested <code>ResourceBundle</code>
88 * @param cl <code>ClassLoader</code> to use for loading this
89 * resource bundle, or <code>null</code> for the default (which
90 * selects the thread context class loader)
91 */
92 public Messages(String name, ClassLoader cl) {
93
94 this.name = name;
95 this.cl = cl;
96
97 }
98
99
100
101
102
103 /***
104 * <p>Set of localized <code>ResourceBundle</code> instances we have ever
105 * retrieved, keyed by <code>Locale</code>.</p>
106 */
107 private Map bundles = new HashMap();
108
109
110 /***
111 * <p>The default <code>Locale</code> for this server.</p>
112 */
113 private Locale defaultLocale = Locale.getDefault();
114
115
116 /***
117 * <p><code>MessageFormat</code> used to perform parameter substitution.</p>
118 */
119 private MessageFormat format = new MessageFormat("");
120
121
122 /***
123 * <p>Log instance for this class.</p>
124 */
125 private transient Log log = null;
126
127
128
129
130
131 /***
132 * <p><code>ClassLoader</code> from which to load the specfied
133 * resource bundle, or <code>null</code> for the thread context
134 * class loader.</p>
135 */
136 private ClassLoader cl = null;
137
138
139 /***
140 * <p>Return the <code>ClassLoader</code> from which to load the
141 * specified resource bundle, or <code>null</code> for the thread
142 * context class loader.</p>
143 */
144 public ClassLoader getClassLoader() {
145
146 return this.cl;
147
148 }
149
150
151 /***
152 * <p>Set the <code>ClassLoader</code> from which to load the
153 * specified resource bundle.</p>
154 *
155 * @param cl The new class loader, or <code>null</code> for the
156 * thread context class loader
157 */
158 public void setClassLoader(ClassLoader cl) {
159
160 this.cl = null;
161 reset();
162
163 }
164
165
166 /***
167 * <p>Name of the resource bundle to be retrieved.</p>
168 */
169 private String name = null;
170
171
172 /***
173 * <p>Return the name of the resource bundle to be retrieved.</p>
174 */
175 public String getName() {
176
177 return this.name;
178
179 }
180
181
182 /***
183 * <p>Set the name of the resource bunde to be retrieved.</p>
184 *
185 * @param name New name of the resource bundle to be retrieved
186 */
187 public void setName(String name) {
188
189 this.name = name;
190 reset();
191
192 }
193
194
195
196
197
198 /***
199 * <p>Retrieve the specified message string for the default locale. If no
200 * message can be found, return <code>null</code>.</p>
201 *
202 * @param key Key to the message string to look up
203 */
204 public String getMessage(String key) {
205
206 return getMessage(key, defaultLocale);
207
208 }
209
210
211 /***
212 * <p>Retrieve the specified message string for the default locale, and
213 * perform parameter substitution with the specified parameters. If no
214 * message can be found, return <code>null</code>.</p>
215 *
216 * @param key Key to the message string to look up
217 * @param params Parameter replacement values
218 */
219 public String getMessage(String key, Object params[]) {
220
221 return getMessage(key, defaultLocale, params);
222
223 }
224
225
226 /***
227 * <p>Retrieve the specified message string for the specified locale. If no
228 * message can be found, return <code>null</code>.</p>
229 *
230 * @param key Key to the message string to look up
231 * @param locale Locale used to localize this message
232 */
233 public String getMessage(String key, Locale locale) {
234
235 ResourceBundle rb = getBundle(locale);
236 try {
237 return rb.getString(key);
238 } catch (MissingResourceException e) {
239 if (log().isWarnEnabled()) {
240 log().warn("Key " + key + " was not found in resource bundle '" +
241 getName() + "' for locale '" + locale + "'");
242 }
243 return null;
244 }
245
246 }
247
248
249 /***
250 * <p>Retrieve the specified message string for the specified locale, and
251 * perform parameter substitution with the specified parameters. If no
252 * message can be found, return <code>null</code>.</p>
253 *
254 * @param key Key to the message string to look up
255 * @param locale Locale used to localize this message
256 * @param params Parameter replacement values
257 */
258 public String getMessage(String key, Locale locale, Object params[]) {
259
260 String message = getMessage(key, locale);
261 if ((message == null) || (params == null) || (params.length < 1)) {
262 return message;
263 }
264 synchronized (format) {
265 format.applyPattern(message);
266 message = format.format(params);
267 }
268 return message;
269
270 }
271
272
273
274
275
276 /***
277 * <p>Return the localized <code>ResourceBundle</code> for the specified
278 * <code>Locale</code>.</p>
279 *
280 * @param locale Locale used to select the appropriate resource bundle
281 */
282 private ResourceBundle getBundle(Locale locale) {
283
284 assert locale != null;
285 ResourceBundle rb = null;
286 ClassLoader rbcl = cl;
287 if (rbcl == null) {
288 rbcl = Thread.currentThread().getContextClassLoader();
289 }
290 synchronized (bundles) {
291 rb = (ResourceBundle) bundles.get(locale);
292 if (rb == null) {
293 try {
294 rb = ResourceBundle.getBundle(name, locale, rbcl);
295 } catch (MissingResourceException e) {
296 rb = ResourceBundle.getBundle(name, defaultLocale, rbcl);
297 }
298 if (rb == null) {
299 if (log().isWarnEnabled()) {
300 log().warn("Resource bundle '" + getName() +
301 "' was not found for locale '" + locale + "'");
302 }
303 } else {
304 bundles.put(locale, rb);
305 }
306 }
307 return rb;
308 }
309
310 }
311
312
313 /***
314 * <p>Return the <code>Log</code> instance for this class.</p>
315 */
316 private Log log() {
317
318 if (log == null) {
319 log = LogFactory.getLog(Messages.class);
320 }
321 return log;
322
323 }
324
325
326 /***
327 * <p>Reset any cached <code>ResourceBundle</code> instances due to a
328 * change in one of the relevant properties.</p>
329 */
330 private void reset() {
331
332 synchronized (bundles) {
333 bundles.clear();
334 }
335
336 }
337
338
339 }