2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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   *    &lt;managed-bean&gt;
38   *      &lt;managed-bean-name&gt;messages&lt;/managed-bean-name&gt;
39   *      &lt;managed-bean-class&gt;
40   *        org.apache.shale.util.Messages
41   *      &lt;/managed-bean-class&gt;
42   *      &lt;managed-bean-scope&gt;application&lt;/managed-bean-scope&gt;
43   *      &lt;managed-property&gt;
44   *        &lt;property-name&gt;name&lt;/property-name&gt;
45   *        &lt;value&gt;com.mycompany.mypackage.Bundle&lt;/value&gt;
46   *      &lt;/managed-property&gt;
47   *    &lt;/managed-bean&gt;
48   * </pre>
49   *
50   * $Id: Messages.java 481403 2006-12-01 21:27:54Z rahul $
51   */
52  public class Messages {
53  
54  
55      // ------------------------------------------------------------ Constructors
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     // ------------------------------------------------------ Instance Variables
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     // -------------------------------------------------------------- Properties
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     // ---------------------------------------------------------- Public Methods
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     // --------------------------------------------------------- Private Methods
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 }