View Javadoc

1   /*
2    * This file is part of Domingo
3    * an Open Source Java-API to Lotus Notes/Domino
4    * hosted at http://domingo.sourceforge.net
5    *
6    * Copyright (c) 2003-2007 Beck et al. projects GmbH Munich, Germany (http://www.bea.de)
7    *
8    * This library is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU Lesser General Public
10   * License as published by the Free Software Foundation; either
11   * version 2.1 of the License, or (at your option) any later version.
12   *
13   * This library is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   * Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public
19   * License along with this library; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21   */
22  
23  package de.bea.domingo.i18n;
24  
25  import java.text.DateFormat;
26  import java.text.MessageFormat;
27  import java.text.ParseException;
28  import java.util.Date;
29  import java.util.Locale;
30  import java.util.MissingResourceException;
31  import java.util.Random;
32  import java.util.ResourceBundle;
33  
34  /***
35   * A class to simplify extracting localized strings, icons
36   * and other common resources from a ResourceBundle.
37   *
38   * @author <a href=mailto:kriede@users.sourceforge.net>Kurt Riede</a>
39   */
40  public final class Resources {
41  
42      /*** A pseudorandom numbers generator. */
43      private static final Random RANDOM = new Random();
44  
45      /*** Local of Resources. */
46      private final Locale locale;
47  
48      /*** Resource bundle referenced by manager. */
49      private ResourceBundle bundle;
50  
51      /*** Base name of resource bundle. */
52      private final String baseName;
53  
54      /*** ClassLoader from which to load resources. */
55      private final ClassLoader classLoader;
56  
57      /*** Whether an exception should be thrown in case of an unknown resource or not. */
58      private boolean fFailOnError;
59  
60      /***
61       * Constructor that builds a manager in default locale.
62       *
63       * @param theBaseName the base name of ResourceBundle
64       */
65      public Resources(final String theBaseName) {
66          this(theBaseName, Locale.getDefault(), null);
67      }
68  
69      /***
70       * Constructor that builds a manager in default locale
71       * using specified ClassLoader.
72       *
73       * @param theBaseName the base name of ResourceBundle
74       * @param theClassLoader the classLoader to load ResourceBundle from
75       */
76      public Resources(final String theBaseName, final ClassLoader theClassLoader) {
77          this(theBaseName, Locale.getDefault(), theClassLoader);
78      }
79  
80      /***
81       * Constructor that builds a manager in specified locale.
82       *
83       * @param theBaseName the base name of ResourceBundle
84       * @param theLocale the Locale for resource bundle
85       */
86      public Resources(final String theBaseName, final Locale theLocale) {
87          this(theBaseName, theLocale, null);
88      }
89  
90      /***
91       * Constructor that builds a manager in specified locale.
92       *
93       * @param theBaseName the base name of ResourceBundle
94       * @param theLocale the Locale for resource bundle
95       * @param theClassLoader the classLoader to load ResourceBundle from
96       */
97      public Resources(final String theBaseName, final Locale theLocale, final ClassLoader theClassLoader) {
98          if (null == theBaseName) {
99              throw new NullPointerException("baseName property is null");
100         }
101         if (null == theLocale) {
102             throw new NullPointerException("locale property is null");
103         }
104         baseName = theBaseName;
105         locale = theLocale;
106         classLoader = theClassLoader;
107     }
108 
109     /***
110      * Whether an exception should be thrown in case of an unknown resource or
111      * not.
112      *
113      * @param failOnError <code>true</code> if an exception should be thrown
114      *            in case of an unknown resource, else <code>false</code>
115      * @return the instance itself
116      */
117     public Resources withFailOnError(final boolean failOnError) {
118         this.fFailOnError = failOnError;
119         return this;
120     }
121 
122     /***
123      * Retrieve a boolean from bundle.
124      *
125      * @param key the key of resource
126      * @param defaultValue the default value if key is missing
127      * @return the resource boolean
128      * @throws MissingResourceException if a resource wasn't found
129      */
130     public boolean getBoolean(final String key, final boolean defaultValue) throws MissingResourceException {
131         try {
132             return getBoolean(key);
133         } catch (final MissingResourceException mre) {
134             return defaultValue;
135         }
136     }
137 
138     /***
139      * Retrieve a boolean from bundle.
140      *
141      * @param key the key of resource
142      * @return the resource boolean
143      * @throws MissingResourceException if a resource wasn't found
144      */
145     public boolean getBoolean(final String key) throws MissingResourceException {
146         final ResourceBundle newBundle = getBundle();
147         final String value = newBundle.getString(key);
148         return value.equalsIgnoreCase("true");
149     }
150 
151     /***
152      * Retrieve a byte from bundle.
153      *
154      * @param key the key of resource
155      * @param defaultValue the default value if key is missing
156      * @return the resource byte
157      * @throws MissingResourceException if a resource wasn't found
158      */
159     public byte getByte(final String key, final byte defaultValue) throws MissingResourceException {
160         try {
161             return getByte(key);
162         } catch (final MissingResourceException mre) {
163             return defaultValue;
164         }
165     }
166 
167     /***
168      * Retrieve a byte from bundle.
169      *
170      * @param key the key of resource
171      * @return the resource byte
172      * @throws MissingResourceException if a resource wasn't found
173      */
174     public byte getByte(final String key) throws MissingResourceException {
175         final ResourceBundle theBundle = getBundle();
176         final String value = theBundle.getString(key);
177         try {
178             return Byte.parseByte(value);
179         } catch (final NumberFormatException nfe) {
180             throw new MissingResourceException("Expecting a byte value but got " + value, String.class.getName(), key);
181         }
182     }
183 
184     /***
185      * Retrieve a char from bundle.
186      *
187      * @param key the key of resource
188      * @param defaultValue the default value if key is missing
189      * @return the resource char
190      * @throws MissingResourceException if a resource wasn't found
191      */
192     public char getChar(final String key, final char defaultValue) throws MissingResourceException {
193         try {
194             return getChar(key);
195         } catch (final MissingResourceException mre) {
196             return defaultValue;
197         }
198     }
199 
200     /***
201      * Retrieve a char from bundle.
202      *
203      * @param key the key of resource
204      * @return the resource char
205      * @throws MissingResourceException if a resource wasn't found
206      */
207     public char getChar(final String key) throws MissingResourceException {
208         final ResourceBundle theBundle = getBundle();
209         final String value = theBundle.getString(key);
210         if (1 != value.length()) {
211             throw new MissingResourceException("Expecting a char value but got " + value, String.class.getName(), key);
212         }
213         return value.charAt(0);
214     }
215 
216     /***
217      * Retrieve a short from bundle.
218      *
219      * @param key the key of resource
220      * @param defaultValue the default value if key is missing
221      * @return the resource short
222      * @throws MissingResourceException if a resource wasn't found
223      */
224     public short getShort(final String key, final short defaultValue) throws MissingResourceException {
225         try {
226             return getShort(key);
227         } catch (final MissingResourceException mre) {
228             return defaultValue;
229         }
230     }
231 
232     /***
233      * Retrieve a short from bundle.
234      *
235      * @param key the key of resource
236      * @return the resource short
237      * @throws MissingResourceException if a resource wasn't found
238      */
239     public short getShort(final String key) throws MissingResourceException {
240         final ResourceBundle theBundle = getBundle();
241         final String value = theBundle.getString(key);
242         try {
243             return Short.parseShort(value);
244         } catch (final NumberFormatException nfe) {
245             throw new MissingResourceException("Expecting a short value but got " + value, String.class.getName(), key);
246         }
247     }
248 
249     /***
250      * Retrieve a integer from bundle.
251      *
252      * @param key the key of resource
253      * @param defaultValue the default value if key is missing
254      * @return the resource integer
255      * @throws MissingResourceException if a resource wasn't found
256      */
257     public int getInteger(final String key, final int defaultValue) throws MissingResourceException {
258         try {
259             return getInteger(key);
260         } catch (final MissingResourceException mre) {
261             return defaultValue;
262         }
263     }
264 
265     /***
266      * Retrieve a integer from bundle.
267      *
268      * @param key the key of resource
269      * @return the resource integer
270      * @throws MissingResourceException if a resource wasn't found
271      */
272     public int getInteger(final String key) throws MissingResourceException {
273         final ResourceBundle theBundle = getBundle();
274         final String value = theBundle.getString(key);
275         try {
276             return Integer.parseInt(value);
277         } catch (final NumberFormatException nfe) {
278             throw new MissingResourceException("Expecting a integer value but got " + value, String.class.getName(), key);
279         }
280     }
281 
282     /***
283      * Retrieve a long from bundle.
284      *
285      * @param key the key of resource
286      * @param defaultValue the default value if key is missing
287      * @return the resource long
288      * @throws MissingResourceException if a resource wasn't found
289      */
290     public long getLong(final String key, final long defaultValue) throws MissingResourceException {
291         try {
292             return getLong(key);
293         } catch (final MissingResourceException mre) {
294             return defaultValue;
295         }
296     }
297 
298     /***
299      * Retrieve a long from bundle.
300      *
301      * @param key the key of resource
302      * @return the resource long
303      * @throws MissingResourceException if a resource wasn't found
304      */
305     public long getLong(final String key) throws MissingResourceException {
306         final ResourceBundle theBundle = getBundle();
307         final String value = theBundle.getString(key);
308         try {
309             return Long.parseLong(value);
310         } catch (final NumberFormatException nfe) {
311             throw new MissingResourceException("Expecting a long value but got " + value, String.class.getName(), key);
312         }
313     }
314 
315     /***
316      * Retrieve a float from bundle.
317      *
318      * @param key the key of resource
319      * @param defaultValue the default value if key is missing
320      * @return the resource float
321      * @throws MissingResourceException if a resource wasn't found
322      */
323     public float getFloat(final String key, final float defaultValue) throws MissingResourceException {
324         try {
325             return getFloat(key);
326         } catch (final MissingResourceException mre) {
327             return defaultValue;
328         }
329     }
330 
331     /***
332      * Retrieve a float from bundle.
333      *
334      * @param key the key of resource
335      * @return the resource float
336      * @throws MissingResourceException if a resource wasn't found
337      */
338     public float getFloat(final String key) throws MissingResourceException {
339         final ResourceBundle theBundle = getBundle();
340         final String value = theBundle.getString(key);
341         try {
342             return Float.parseFloat(value);
343         } catch (final NumberFormatException nfe) {
344             throw new MissingResourceException("Expecting a float value but got " + value, String.class.getName(), key);
345         }
346     }
347 
348     /***
349      * Retrieve a double from bundle.
350      *
351      * @param key the key of resource
352      * @param defaultValue the default value if key is missing
353      * @return the resource double
354      * @throws MissingResourceException if a resource wasn't found
355      */
356     public double getDouble(final String key, final double defaultValue) throws MissingResourceException {
357         try {
358             return getDouble(key);
359         } catch (final MissingResourceException mre) {
360             return defaultValue;
361         }
362     }
363 
364     /***
365      * Retrieve a double from bundle.
366      *
367      * @param key the key of resource
368      * @return the resource double
369      * @throws MissingResourceException if a resource wasn't found
370      */
371     public double getDouble(final String key) throws MissingResourceException {
372         final ResourceBundle theBundle = getBundle();
373         final String value = theBundle.getString(key);
374         try {
375             return Double.parseDouble(value);
376         } catch (final NumberFormatException nfe) {
377             throw new MissingResourceException("Expecting a double value but got " + value, String.class.getName(), key);
378         }
379     }
380 
381     /***
382      * Retrieve a date from bundle.
383      *
384      * @param key the key of resource
385      * @param defaultValue the default value if key is missing
386      * @return the resource date
387      * @throws MissingResourceException if a resource wasn't found
388      */
389     public Date getDate(final String key, final Date defaultValue) throws MissingResourceException {
390         try {
391             return getDate(key);
392         } catch (final MissingResourceException mre) {
393             return defaultValue;
394         }
395     }
396 
397     /***
398      * Retrieve a date from bundle.
399      *
400      * @param key the key of resource
401      * @return the resource date
402      * @throws MissingResourceException if a resource wasn't found
403      */
404     public Date getDate(final String key) throws MissingResourceException {
405         final ResourceBundle theBundle = getBundle();
406         final String value = theBundle.getString(key);
407         try {
408             final DateFormat format = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
409             return format.parse(value);
410         } catch (final ParseException pe) {
411             throw new MissingResourceException("Expecting a date value but got " + value, String.class.getName(), key);
412         }
413     }
414 
415     /***
416      * Retrieve a time from bundle.
417      *
418      * @param key the key of resource
419      * @param defaultValue the default value if key is missing
420      * @return the resource time
421      * @throws MissingResourceException if a resource wasn't found
422      */
423     public Date getTime(final String key, final Date defaultValue) throws MissingResourceException {
424         try {
425             return getTime(key);
426         } catch (final MissingResourceException mre) {
427             return defaultValue;
428         }
429     }
430 
431     /***
432      * Retrieve a time from bundle.
433      *
434      * @param key the key of resource
435      * @return the resource time
436      * @throws MissingResourceException if a resource wasn't found
437      */
438     public Date getTime(final String key) throws MissingResourceException {
439         final ResourceBundle theBundle = getBundle();
440         final String value = theBundle.getString(key);
441         try {
442             final DateFormat format = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
443             return format.parse(value);
444         } catch (final ParseException pe) {
445             throw new MissingResourceException("Expecting a time value but got " + value, String.class.getName(), key);
446         }
447     }
448 
449     /***
450      * Retrieve a time from bundle.
451      *
452      * @param key the key of resource
453      * @param defaultValue the default value if key is missing
454      * @return the resource time
455      * @throws MissingResourceException if a resource wasn't found
456      */
457     public Date getDateTime(final String key, final Date defaultValue) throws MissingResourceException {
458         try {
459             return getDateTime(key);
460         } catch (final MissingResourceException mre) {
461             return defaultValue;
462         }
463     }
464 
465     /***
466      * Retrieve a date + time from bundle.
467      *
468      * @param key the key of resource
469      * @return the resource date + time
470      * @throws MissingResourceException if a resource wasn't found
471      */
472     public Date getDateTime(final String key) throws MissingResourceException {
473         final ResourceBundle theBundle = getBundle();
474         final String value = theBundle.getString(key);
475         try {
476             final DateFormat format = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, locale);
477             return format.parse(value);
478         } catch (final ParseException pe) {
479             throw new MissingResourceException("Expecting a date/time value but got " + value, String.class.getName(), key);
480         }
481     }
482 
483     /***
484      * Retrieve a raw string from bundle.
485      *
486      * @param key the key of resource
487      * @return the resource string
488      * @throws MissingResourceException if a resource wasn't found
489      */
490     public String getString(final String key) throws MissingResourceException {
491         final Object[] args = new Object[] {};
492         return format(key, args);
493     }
494 
495     /***
496      * Retrieve a string from resource bundle and format it with specified arguments.
497      *
498      * @param key the key for resource
499      * @param arg1 an argument
500      * @return the formatted string
501      */
502     public String getString(final String key, final Object arg1) {
503         final Object[] args = new Object[] {arg1 };
504         return format(key, args);
505     }
506 
507     /***
508      * Retrieve a string from resource bundle and format it with specified arguments.
509      *
510      * @param key the key for resource
511      * @param arg1 an argument
512      * @param arg2 an argument
513      * @return the formatted string
514      */
515     public String getString(final String key, final Object arg1, final Object arg2) {
516         final Object[] args = new Object[] {arg1, arg2 };
517         return format(key, args);
518     }
519 
520     /***
521      * Retrieve a string from resource bundle and format it with specified arguments.
522      *
523      * @param key the key for resource
524      * @param arg1 an argument
525      * @param arg2 an argument
526      * @param arg3 an argument
527      * @return the formatted string
528      */
529     public String getString(final String key, final Object arg1, final Object arg2, final Object arg3) {
530         final Object[] args = new Object[] {arg1, arg2, arg3 };
531         return format(key, args);
532     }
533 
534     /***
535      * Retrieve a string from resource bundle and format it with specified arguments.
536      *
537      * @param key the key for resource
538      * @param arg1 an argument
539      * @param arg2 an argument
540      * @param arg3 an argument
541      * @param arg4 an argument
542      * @return the formatted string
543      */
544     public String getString(final String key, final Object arg1, final Object arg2, final Object arg3, final Object arg4) {
545         final Object[] args = new Object[] {arg1, arg2, arg3, arg4 };
546         return format(key, args);
547     }
548 
549     /***
550      * Retrieve a string from resource bundle and format it with specified arguments.
551      *
552      * @param key the key for resource
553      * @param args an array of arguments
554      * @return the formatted string
555      * @throws MissingResourceException if {@link #withFailOnError(boolean)} is true and the requested resource wasn't found
556      * @see #withFailOnError(boolean)
557      */
558     public String format(final String key, final Object[] args) throws MissingResourceException {
559         try {
560             final String pattern = getPatternString(key);
561             return MessageFormat.format(pattern, args);
562         } catch (final MissingResourceException mre) {
563             if (fFailOnError) {
564                 throw mre;
565             }
566             final StringBuffer sb = new StringBuffer();
567             sb.append("Unknown resource. Bundle: '");
568             sb.append(baseName);
569             sb.append("' key: '");
570             sb.append(key);
571             sb.append("' arguments: '");
572             for (int i = 0; i < args.length; i++) {
573                 if (0 != i) {
574                     sb.append("', '");
575                 }
576                 sb.append(args[i]);
577             }
578             sb.append("' Reason: ");
579             sb.append(mre);
580             return sb.toString();
581         }
582     }
583 
584     /***
585      * Retrieve underlying ResourceBundle.
586      * If bundle has not been loaded it will be loaded by this method.
587      * Access is given in case other resources need to be extracted
588      * that this Manager does not provide simplified access to.
589      *
590      * @return the ResourceBundle
591      * @throws MissingResourceException if an error occurs
592      */
593     public ResourceBundle getBundle() throws MissingResourceException {
594         if (null == bundle) {
595             // bundle wasn't cached, so load it, cache it, and return it.
596             ClassLoader theClassLoader = this.classLoader;
597             if (null == theClassLoader) {
598                 theClassLoader = Thread.currentThread().getContextClassLoader();
599             }
600             if (null != theClassLoader) {
601                 bundle = ResourceBundle.getBundle(baseName, locale, theClassLoader);
602             } else {
603                 bundle = ResourceBundle.getBundle(baseName, locale);
604             }
605         }
606         return bundle;
607     }
608 
609     /***
610      * Utility method to retrieve a string from ResourceBundle.
611      * If the key is a single string then that will be returned.
612      * If key refers to string array then a random string will be chosen.
613      * Other types cause an exception.
614      *
615      * @param key the key to resource
616      * @return the string resource
617      * @throws MissingResourceException if an error occurs
618      */
619     private String getPatternString(final String key) throws MissingResourceException {
620         final ResourceBundle theBundle = getBundle();
621         final Object object = theBundle.getObject(key);
622         // is the resource a single string
623         if (object instanceof String) {
624             return (String) object;
625         } else if (object instanceof String[]) {
626             //if string array then randomly pick one
627             final String[] strings = (String[]) object;
628             return strings[RANDOM.nextInt(strings.length)];
629         } else {
630             throw new MissingResourceException("Unable to find resource of appropriate type.", String.class.getName(), key);
631         }
632     }
633 }