1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package net.sf.navigator.util;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25
26 import java.io.Serializable;
27 import java.text.MessageFormat;
28 import java.util.HashMap;
29 import java.util.Locale;
30
31 /**
32 * General purpose abstract class that describes an API for retrieving
33 * Locale-sensitive messages from underlying resource locations of an
34 * unspecified design, and optionally utilizing the <code>MessageFormat</code>
35 * class to produce internationalized messages with parametric replacement.
36 * <p>
37 * Calls to <code>getMessage()</code> variants without a <code>Locale</code>
38 * argument are presumed to be requesting a message string in the default
39 * <code>Locale</code> for this JVM.
40 * <p>
41 * Calls to <code>getMessage()</code> with an unknown key, or an unknown
42 * <code>Locale</code> will return <code>null</code> if the
43 * <code>returnNull</code> property is set to <code>true</code>. Otherwise,
44 * a suitable error message will be returned instead.
45 * <p>
46 * <strong>IMPLEMENTATION NOTE</strong> - Classes that extend this class
47 * must be Serializable so that instances may be used in distributable
48 * application server environments.
49 *
50 * @version $Revision: 1.2 $ $Date: 2006/05/12 19:52:25 $
51 */
52 public abstract class MessageResources implements Serializable {
53
54
55
56 /**
57 * Commons Logging instance.
58 */
59 protected static Log log = LogFactory.getLog(MessageResources.class);
60
61 /**
62 * The configuration parameter used to initialize this MessageResources.
63 */
64 protected String config = null;
65
66 /**
67 * The configuration parameter used to initialize this MessageResources.
68 * @return parameter used to initialize this MessageResources
69 */
70 public String getConfig() {
71 return (this.config);
72 }
73
74 /**
75 * The default Locale for our environment.
76 */
77 protected Locale defaultLocale = Locale.getDefault();
78
79 /**
80 * The <code>MessageResourcesFactory</code> that created this instance.
81 */
82 protected MessageResourcesFactory factory = null;
83
84 /**
85 * The <code>MessageResourcesFactory</code> that created this instance.
86 * @return <code>MessageResourcesFactory</code> that created instance
87 */
88 public MessageResourcesFactory getFactory() {
89 return (this.factory);
90 }
91
92 /**
93 * The set of previously created MessageFormat objects, keyed by the
94 * key computed in <code>messageKey()</code>.
95 */
96 protected HashMap formats = new HashMap();
97
98 /**
99 * Indicate is a <code>null</code> is returned instead of an error message string
100 * when an unknown Locale or key is requested.
101 */
102 protected boolean returnNull = false;
103
104 /**
105 * Indicates that a <code>null</code> is returned instead of an error message string
106 * if an unknown Locale or key is requested.
107 * @return true if null is returned if unknown key or locale is requested
108 */
109 public boolean getReturnNull() {
110 return (this.returnNull);
111 }
112
113 /**
114 * Indicates that a <code>null</code> is returned instead of an error message string
115 * if an unknown Locale or key is requested.
116 * @param returnNull true Indicates that a <code>null</code> is returned
117 * if an unknown Locale or key is requested.
118 */
119 public void setReturnNull(boolean returnNull) {
120 this.returnNull = returnNull;
121 }
122
123
124
125 /**
126 * Construct a new MessageResources according to the specified parameters.
127 *
128 * @param factory The MessageResourcesFactory that created us
129 * @param config The configuration parameter for this MessageResources
130 */
131 public MessageResources(MessageResourcesFactory factory, String config) {
132
133 this(factory, config, false);
134
135 }
136
137 /**
138 * Construct a new MessageResources according to the specified parameters.
139 *
140 * @param factory The MessageResourcesFactory that created us
141 * @param config The configuration parameter for this MessageResources
142 * @param returnNull The returnNull property we should initialize with
143 */
144 public MessageResources(
145 MessageResourcesFactory factory,
146 String config,
147 boolean returnNull) {
148
149 super();
150 this.factory = factory;
151 this.config = config;
152 this.returnNull = returnNull;
153
154 }
155
156
157
158 /**
159 * Returns a text message for the specified key, for the default Locale.
160 *
161 * @param key The message key to look up
162 */
163 public String getMessage(String key) {
164
165 return this.getMessage((Locale) null, key, null);
166
167 }
168
169 /**
170 * Returns a text message after parametric replacement of the specified
171 * parameter placeholders.
172 *
173 * @param key The message key to look up
174 * @param args An array of replacement parameters for placeholders
175 */
176 public String getMessage(String key, Object args[]) {
177
178 return this.getMessage((Locale) null, key, args);
179
180 }
181
182 /**
183 * Returns a text message after parametric replacement of the specified
184 * parameter placeholders.
185 *
186 * @param key The message key to look up
187 * @param arg0 The replacement for placeholder {0} in the message
188 */
189 public String getMessage(String key, Object arg0) {
190
191 return this.getMessage((Locale) null, key, arg0);
192
193 }
194
195 /**
196 * Returns a text message after parametric replacement of the specified
197 * parameter placeholders.
198 *
199 * @param key The message key to look up
200 * @param arg0 The replacement for placeholder {0} in the message
201 * @param arg1 The replacement for placeholder {1} in the message
202 */
203 public String getMessage(String key, Object arg0, Object arg1) {
204
205 return this.getMessage((Locale) null, key, arg0, arg1);
206
207 }
208
209 /**
210 * Returns a text message after parametric replacement of the specified
211 * parameter placeholders.
212 *
213 * @param key The message key to look up
214 * @param arg0 The replacement for placeholder {0} in the message
215 * @param arg1 The replacement for placeholder {1} in the message
216 * @param arg2 The replacement for placeholder {2} in the message
217 */
218 public String getMessage(String key, Object arg0, Object arg1, Object arg2) {
219
220 return this.getMessage((Locale) null, key, arg0, arg1, arg2);
221
222 }
223
224 /**
225 * Returns a text message after parametric replacement of the specified
226 * parameter placeholders.
227 *
228 * @param key The message key to look up
229 * @param arg0 The replacement for placeholder {0} in the message
230 * @param arg1 The replacement for placeholder {1} in the message
231 * @param arg2 The replacement for placeholder {2} in the message
232 * @param arg3 The replacement for placeholder {3} in the message
233 */
234 public String getMessage(
235 String key,
236 Object arg0,
237 Object arg1,
238 Object arg2,
239 Object arg3) {
240
241 return this.getMessage((Locale) null, key, arg0, arg1, arg2, arg3);
242 }
243
244 /**
245 * Returns a text message after parametric replacement of the specified
246 * parameter placeholders.
247 *
248 * @param key The message key to look up
249 * @param arg0 The replacement for placeholder {0} in the message
250 * @param arg1 The replacement for placeholder {1} in the message
251 * @param arg2 The replacement for placeholder {2} in the message
252 * @param arg3 The replacement for placeholder {3} in the message
253 * @param arg4 The replacement for placeholder {4} in the message
254 */
255 public String getMessage(
256 String key,
257 Object arg0,
258 Object arg1,
259 Object arg2,
260 Object arg3,
261 Object arg4) {
262
263 return this.getMessage((Locale) null, key, arg0, arg1, arg2, arg3, arg4);
264 }
265
266 /**
267 * Returns a text message for the specified key, for the default Locale.
268 * A null string result will be returned by this method if no relevant
269 * message resource is found for this key or Locale, if the
270 * <code>returnNull</code> property is set. Otherwise, an appropriate
271 * error message will be returned.
272 * <p>
273 * This method must be implemented by a concrete subclass.
274 *
275 * @param locale The requested message Locale, or <code>null</code>
276 * for the system default Locale
277 * @param key The message key to look up
278 */
279 public abstract String getMessage(Locale locale, String key);
280
281 /**
282 * Returns a text message after parametric replacement of the specified
283 * parameter placeholders. A null string result will be returned by
284 * this method if no resource bundle has been configured.
285 *
286 * @param locale The requested message Locale, or <code>null</code>
287 * for the system default Locale
288 * @param key The message key to look up
289 * @param args An array of replacement parameters for placeholders
290 */
291 public String getMessage(Locale locale, String key, Object args[]) {
292
293
294 if (locale == null) {
295 locale = defaultLocale;
296 }
297
298 MessageFormat format = null;
299 String formatKey = messageKey(locale, key);
300
301 synchronized (formats) {
302 format = (MessageFormat) formats.get(formatKey);
303 if (format == null) {
304 String formatString = getMessage(locale, key);
305
306 if (formatString == null) {
307 return returnNull ? null : ("???" + formatKey + "???");
308 }
309
310 format = new MessageFormat(escape(formatString));
311 format.setLocale(locale);
312 formats.put(formatKey, format);
313 }
314
315 }
316
317 return format.format(args);
318 }
319
320 /**
321 * Returns a text message after parametric replacement of the specified
322 * parameter placeholders. A null string result will never be returned
323 * by this method.
324 *
325 * @param locale The requested message Locale, or <code>null</code>
326 * for the system default Locale
327 * @param key The message key to look up
328 * @param arg0 The replacement for placeholder {0} in the message
329 */
330 public String getMessage(Locale locale, String key, Object arg0) {
331 return this.getMessage(locale, key, new Object[] { arg0 });
332 }
333
334 /**
335 * Returns a text message after parametric replacement of the specified
336 * parameter placeholders. A null string result will never be returned
337 * by this method.
338 *
339 * @param locale The requested message Locale, or <code>null</code>
340 * for the system default Locale
341 * @param key The message key to look up
342 * @param arg0 The replacement for placeholder {0} in the message
343 * @param arg1 The replacement for placeholder {1} in the message
344 */
345 public String getMessage(Locale locale, String key, Object arg0, Object arg1) {
346 return this.getMessage(locale, key, new Object[] { arg0, arg1 });
347 }
348
349 /**
350 * Returns a text message after parametric replacement of the specified
351 * parameter placeholders. A null string result will never be returned
352 * by this method.
353 *
354 * @param locale The requested message Locale, or <code>null</code>
355 * for the system default Locale
356 * @param key The message key to look up
357 * @param arg0 The replacement for placeholder {0} in the message
358 * @param arg1 The replacement for placeholder {1} in the message
359 * @param arg2 The replacement for placeholder {2} in the message
360 */
361 public String getMessage(
362 Locale locale,
363 String key,
364 Object arg0,
365 Object arg1,
366 Object arg2) {
367
368 return this.getMessage(locale, key, new Object[] { arg0, arg1, arg2 });
369 }
370
371 /**
372 * Returns a text message after parametric replacement of the specified
373 * parameter placeholders. A null string result will never be returned
374 * by this method.
375 *
376 * @param locale The requested message Locale, or <code>null</code>
377 * for the system default Locale
378 * @param key The message key to look up
379 * @param arg0 The replacement for placeholder {0} in the message
380 * @param arg1 The replacement for placeholder {1} in the message
381 * @param arg2 The replacement for placeholder {2} in the message
382 * @param arg3 The replacement for placeholder {3} in the message
383 */
384 public String getMessage(
385 Locale locale,
386 String key,
387 Object arg0,
388 Object arg1,
389 Object arg2,
390 Object arg3) {
391
392 return this.getMessage(locale, key, new Object[] { arg0, arg1, arg2, arg3 });
393 }
394
395 /**
396 * Returns a text message after parametric replacement of the specified
397 * parameter placeholders. A null string result will never be returned
398 * by this method.
399 *
400 * @param locale The requested message Locale, or <code>null</code>
401 * for the system default Locale
402 * @param key The message key to look up
403 * @param arg0 The replacement for placeholder {0} in the message
404 * @param arg1 The replacement for placeholder {1} in the message
405 * @param arg2 The replacement for placeholder {2} in the message
406 * @param arg3 The replacement for placeholder {3} in the message
407 * @param arg4 The replacement for placeholder {4} in the message
408 */
409 public String getMessage(
410 Locale locale,
411 String key,
412 Object arg0,
413 Object arg1,
414 Object arg2,
415 Object arg3,
416 Object arg4) {
417
418 return this.getMessage(locale, key, new Object[] { arg0, arg1, arg2, arg3, arg4 });
419 }
420
421 /**
422 * Return <code>true</code> if there is a defined message for the specified
423 * key in the system default locale.
424 *
425 * @param key The message key to look up
426 */
427 public boolean isPresent(String key) {
428
429 return this.isPresent(null, key);
430
431 }
432
433 /**
434 * Return <code>true</code> if there is a defined message for the specified
435 * key in the specified Locale.
436 *
437 * @param locale The requested message Locale, or <code>null</code>
438 * for the system default Locale
439 * @param key The message key to look up
440 */
441 public boolean isPresent(Locale locale, String key) {
442
443 String message = getMessage(locale, key);
444
445 if (message == null) {
446 return false;
447
448 } else if (message.startsWith("???") && message.endsWith("???")) {
449 return false;
450
451 } else {
452 return true;
453 }
454
455 }
456
457
458
459 /**
460 * Escape any single quote characters that are included in the specified
461 * message string.
462 *
463 * @param string The string to be escaped
464 */
465 protected String escape(String string) {
466
467 if ((string == null) || (string.indexOf('\'') < 0)) {
468 return string;
469 }
470
471 int n = string.length();
472 StringBuffer sb = new StringBuffer(n);
473
474 for (int i = 0; i < n; i++) {
475 char ch = string.charAt(i);
476
477 if (ch == '\'') {
478 sb.append('\'');
479 }
480
481 sb.append(ch);
482 }
483
484 return sb.toString();
485
486 }
487
488 /**
489 * Compute and return a key to be used in caching information by a Locale.
490 * <strong>NOTE</strong> - The locale key for the default Locale in our
491 * environment is a zero length String.
492 *
493 * @param locale The locale for which a key is desired
494 */
495 protected String localeKey(Locale locale) {
496 return (locale == null) ? "" : locale.toString();
497 }
498
499 /**
500 * Compute and return a key to be used in caching information
501 * by Locale and message key.
502 *
503 * @param locale The Locale for which this format key is calculated
504 * @param key The message key for which this format key is calculated
505 */
506 protected String messageKey(Locale locale, String key) {
507
508 return (localeKey(locale) + "." + key);
509
510 }
511
512 /**
513 * Compute and return a key to be used in caching information
514 * by locale key and message key.
515 *
516 * @param localeKey The locale key for which this cache key is calculated
517 * @param key The message key for which this cache key is calculated
518 */
519 protected String messageKey(String localeKey, String key) {
520
521 return (localeKey + "." + key);
522
523 }
524
525
526
527 /**
528 * The default MessageResourcesFactory used to create MessageResources
529 * instances.
530 */
531 protected static MessageResourcesFactory defaultFactory = null;
532
533 /**
534 * Create and return an instance of <code>MessageResources</code> for the
535 * created by the default <code>MessageResourcesFactory</code>.
536 *
537 * @param config Configuration parameter for this message bundle.
538 */
539 public synchronized static MessageResources getMessageResources(String config) {
540
541 if (defaultFactory == null) {
542 defaultFactory = MessageResourcesFactory.createFactory();
543 }
544
545 return defaultFactory.createResources(config);
546 }
547
548 /**
549 * Log a message to the Writer that has been configured for our use.
550 *
551 * @param message The message to be logged
552 */
553 public void log(String message) {
554 log.debug(message);
555 }
556
557 /**
558 * Log a message and exception to the Writer that has been configured
559 * for our use.
560 *
561 * @param message The message to be logged
562 * @param throwable The exception to be logged
563 */
564 public void log(String message, Throwable throwable) {
565 log.debug(message, throwable);
566 }
567
568 }