1 package org.apache.turbine.services.localization;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.util.Hashtable;
58 import java.util.Locale;
59 import java.util.ResourceBundle;
60 import java.util.MissingResourceException;
61 import javax.servlet.http.HttpServletRequest;
62
63 import org.apache.turbine.services.InitializationException;
64 import org.apache.turbine.services.TurbineBaseService;
65 import org.apache.turbine.services.resources.TurbineResources;
66 import org.apache.turbine.util.RunData;
67 import org.apache.turbine.util.Log;
68 import org.apache.turbine.util.StringUtils;
69
70 /***
71 * <p>This class is the single point of access to all localization
72 * resources. It caches different ResourceBundles for different
73 * Locales.</p>
74 *
75 * <p>Usage example:</p>
76 *
77 * <blockquote><code><pre>
78 * LocalizationService ls = (LocalizationService) TurbineServices
79 * .getInstance().getService(LocalizationService.SERVICE_NAME);
80 * </pre></code></blockquote>
81 *
82 * <p>Then call one of four methods to retrieve a ResourceBundle:
83 *
84 * <ul>
85 * <li>getBundle("MyBundleName")</li>
86 * <li>getBundle("MyBundleName", httpAcceptLanguageHeader)</li>
87 * <li>etBundle("MyBundleName", HttpServletRequest)</li>
88 * <li>getBundle("MyBundleName", Locale)</li>
89 * <li>etc.</li>
90 * </ul></p>
91 *
92 * @author <a href="mailto:jm@mediaphil.de">Jonas Maurus</a>
93 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
94 * @author <a href="mailto:novalidemail@foo.com">Frank Y. Kim</a>
95 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
96 */
97 public class TurbineLocalizationService
98 extends TurbineBaseService
99 implements LocalizationService
100 {
101 /***
102 * The ResourceBundles in this service.
103 * Key=bundle name
104 * Value=Hashtable containing ResourceBundles keyed by Locale.
105 */
106 private Hashtable bundles = null;
107
108 /***
109 * The list of default bundles to search.
110 */
111 private String[] bundleNames = null;
112
113 /***
114 * The name of the default locale to use (includes language and
115 * country).
116 */
117 private Locale defaultLocale = null;
118
119 /*** The name of the default language to use. */
120 private String defaultLanguage = null;
121
122 /*** The name of the default country to use. */
123 private String defaultCountry = null;
124
125 /***
126 * Constructor.
127 */
128 public TurbineLocalizationService()
129 {
130 bundles = new Hashtable();
131 }
132
133 /***
134 * Called the first time the Service is used.
135 */
136 public void init()
137 throws InitializationException
138 {
139 initBundleNames(null);
140
141 Locale jvmDefault = Locale.getDefault();
142 defaultLanguage = TurbineResources
143 .getString("locale.default.language",
144 jvmDefault.getLanguage()).trim();
145 defaultCountry = TurbineResources
146 .getString("locale.default.country",
147 jvmDefault.getCountry()).trim();
148 defaultLocale = new Locale(defaultLanguage, defaultCountry);
149 setInit(true);
150 }
151
152
153 /***
154 * Initialize list of default bundle names.
155 *
156 * @param names Ignored.
157 */
158 protected void initBundleNames(String[] ignored)
159 {
160 bundleNames =
161 TurbineResources.getStringArray("locale.default.bundles");
162 String name = TurbineResources.getString("locale.default.bundle");
163
164 if (name != null && name.length() > 0)
165 {
166 // Using old-style single bundle name property.
167 if (bundleNames == null || bundleNames.length <= 0)
168 {
169 bundleNames = new String[] { name };
170 }
171 else
172 {
173 // Prepend "default" bundle name.
174 String[] array = new String[bundleNames.length + 1];
175 array[0] = name;
176 System.arraycopy(bundleNames, 0, array, 1, bundleNames.length);
177 bundleNames = array;
178 }
179 }
180 if (bundleNames == null)
181 {
182 bundleNames = new String[0];
183 }
184 }
185
186 /***
187 * Retrieves the name of the default bundle (as specified in the
188 * config file).
189 * @see org.apache.turbine.services.localization.LocalizationService#getDefaultBundleName()
190 */
191 public String getDefaultBundleName()
192 {
193 return (bundleNames.length > 0 ? bundleNames[0] : "");
194 }
195
196 /***
197 * This method returns a ResourceBundle given the bundle name
198 * "DEFAULT" and the default Locale information supplied in
199 * TurbineProperties.
200 *
201 * @return A localized ResourceBundle.
202 */
203 public ResourceBundle getBundle()
204 {
205 return getBundle(getDefaultBundleName(), (Locale) null);
206 }
207
208 /***
209 * This method returns a ResourceBundle given the bundle name and
210 * the default Locale information supplied in TurbineProperties.
211 *
212 * @param bundleName Name of bundle.
213 * @return A localized ResourceBundle.
214 */
215 public ResourceBundle getBundle(String bundleName)
216 {
217 return getBundle(bundleName, (Locale) null);
218 }
219
220 /***
221 * This method returns a ResourceBundle given the bundle name and
222 * the Locale information supplied in the HTTP "Accept-Language"
223 * header.
224 *
225 * @param bundleName Name of bundle.
226 * @param languageHeader A String with the language header.
227 * @return A localized ResourceBundle.
228 */
229 public ResourceBundle getBundle(String bundleName, String languageHeader)
230 {
231 return getBundle(bundleName, getLocale(languageHeader));
232 }
233
234 /***
235 * This method returns a ResourceBundle given the Locale
236 * information supplied in the HTTP "Accept-Language" header which
237 * is stored in HttpServletRequest.
238 *
239 * @param req HttpServletRequest.
240 * @return A localized ResourceBundle.
241 */
242 public ResourceBundle getBundle(HttpServletRequest req)
243 {
244 return getBundle(getDefaultBundleName(), getLocale(req));
245 }
246
247 /***
248 * This method returns a ResourceBundle given the bundle name and
249 * the Locale information supplied in the HTTP "Accept-Language"
250 * header which is stored in HttpServletRequest.
251 *
252 * @param bundleName Name of the bundle to use if the request's
253 * locale cannot be resolved.
254 * @param req HttpServletRequest.
255 * @return A localized ResourceBundle.
256 */
257 public ResourceBundle getBundle(String bundleName, HttpServletRequest req)
258 {
259 return getBundle(bundleName, getLocale(req));
260 }
261
262 /***
263 * This method returns a ResourceBundle given the Locale
264 * information supplied in the HTTP "Accept-Language" header which
265 * is stored in RunData.
266 *
267 * @param data Turbine information.
268 * @return A localized ResourceBundle.
269 */
270 public ResourceBundle getBundle(RunData data)
271 {
272 return getBundle(getDefaultBundleName(), getLocale(data.getRequest()));
273 }
274
275 /***
276 * This method returns a ResourceBundle given the bundle name and
277 * the Locale information supplied in the HTTP "Accept-Language"
278 * header which is stored in RunData.
279 *
280 * @param bundleName Name of bundle.
281 * @param data Turbine information.
282 * @return A localized ResourceBundle.
283 */
284 public ResourceBundle getBundle(String bundleName, RunData data)
285 {
286 return getBundle(bundleName, getLocale(data.getRequest()));
287 }
288
289 /***
290 * This method returns a ResourceBundle for the given bundle name
291 * and the given Locale.
292 *
293 * @param bundleName Name of bundle.
294 * @param locale A Locale.
295 * @return A localized ResourceBundle.
296 */
297 public ResourceBundle getBundle(String bundleName, Locale locale)
298 {
299 // Assure usable inputs.
300 bundleName = (bundleName == null ? getDefaultBundleName() : bundleName.trim());
301 if (locale == null)
302 {
303 locale = getLocale((String) null);
304 }
305
306 if ( bundles.containsKey(bundleName) )
307 {
308 Hashtable locales = (Hashtable)bundles.get(bundleName);
309
310 if ( locales.containsKey(locale) )
311 {
312 return (ResourceBundle)locales.get(locale);
313 }
314 else
315 {
316 // Try to create a ResourceBundle for this Locale.
317 ResourceBundle rb = ResourceBundle.getBundle(bundleName,
318 locale);
319
320 // Cache the ResourceBundle in memory.
321 locales.put( rb.getLocale(), rb );
322
323 return rb;
324 }
325 }
326 else
327 {
328 // Try to create a ResourceBundle for this Locale.
329 ResourceBundle rb = ResourceBundle.getBundle(bundleName,
330 locale);
331
332 // Cache the ResourceBundle in memory.
333 Hashtable ht = new Hashtable();
334 ht.put( locale, rb );
335
336 // Can't call getLocale(), because that is jdk2. This
337 // needs to be changed back, since the above approach
338 // caches extra Locale and Bundle objects.
339 // ht.put( rb.getLocale(), rb );
340
341 bundles.put( bundleName, ht );
342
343 return rb;
344 }
345 }
346
347 /***
348 * This method sets the name of the first bundle in the search
349 * list (the "default" bundle).
350 *
351 * @param defaultBundle Name of default bundle.
352 */
353 public void setBundle(String defaultBundle)
354 {
355 if (bundleNames.length > 0)
356 {
357 bundleNames[0] = defaultBundle;
358 }
359 else
360 {
361 synchronized (this)
362 {
363 if (bundleNames.length <= 0)
364 {
365 bundleNames = new String[] { defaultBundle };
366 }
367 }
368 }
369 }
370
371 /***
372 * @see org.apache.turbine.services.localization.LocalizationService#getLocale(HttpServletRequest)
373 */
374 public final Locale getLocale(HttpServletRequest req)
375 {
376 return getLocale(req.getHeader(ACCEPT_LANGUAGE));
377 }
378
379 /***
380 * @see org.apache.turbine.services.localization.LocalizationService#getLocale(String)
381 */
382 public Locale getLocale(String header)
383 {
384 if (!StringUtils.isEmpty(header))
385 {
386 LocaleTokenizer tok = new LocaleTokenizer(header);
387 if (tok.hasNext())
388 {
389 return (Locale) tok.next();
390 }
391 }
392
393 // Couldn't parse locale.
394 return defaultLocale;
395 }
396
397
398 /***
399 * @exception MissingResourceException Specified key cannot be matched.
400 * @see org.apache.turbine.services.localization.LocalizationService#getString(String, Locale, String)
401 */
402 public String getString(String bundleName, Locale locale, String key)
403 {
404 String value = null;
405
406 if (locale == null)
407 {
408 locale = getLocale((String) null);
409 }
410
411 // Look for text in requested bundle.
412 ResourceBundle rb = getBundle(bundleName, locale);
413 value = getStringOrNull(rb, key);
414
415 // Look for text in list of default bundles.
416 if (value == null && bundleNames.length > 0)
417 {
418 String name;
419 for (int i = 0; i < bundleNames.length; i++)
420 {
421 name = bundleNames[i];
422 //System.out.println("getString(): name=" + name +
423 // ", locale=" + locale + ", i=" + i);
424 if (!name.equals(bundleName))
425 {
426 rb = getBundle(name, locale);
427 value = getStringOrNull(rb, key);
428 if (value != null)
429 {
430 locale = rb.getLocale();
431 break;
432 }
433 }
434 }
435 }
436
437 if (value == null)
438 {
439 String loc = locale.toString();
440 Log.debug(LocalizationService.SERVICE_NAME +
441 " noticed missing resource: " +
442 "bundleName=" + bundleName + ", locale=" + loc +
443 ", key=" + key);
444 // Text not found in requested or default bundles.
445 throw new MissingResourceException(bundleName, loc, key);
446 }
447
448 return value;
449 }
450
451 /***
452 * Gets localized text from a bundle if it's there. Otherwise,
453 * returns <code>null</code> (ignoring a possible
454 * <code>MissingResourceException</code>).
455 */
456 protected final String getStringOrNull(ResourceBundle rb, String key)
457 {
458 if (rb != null)
459 {
460 try
461 {
462 return rb.getString(key);
463 }
464 catch (MissingResourceException ignored)
465 {
466 }
467 }
468 return null;
469 }
470
471 }
This page was automatically generated by Maven