Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/axis/i18n/ProjectResourceBundle.java


1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.axis.i18n;
18  
19  import org.apache.axis.components.logger.LogFactory;
20  import org.apache.commons.logging.Log;
21  
22  import java.util.Enumeration;
23  import java.util.HashSet;
24  import java.util.Hashtable;
25  import java.util.Iterator;
26  import java.util.Locale;
27  import java.util.MissingResourceException;
28  import java.util.ResourceBundle;
29  
30  /**
31   * <p>Wrapper class for resource bundles. Property files are used to store
32   * resource strings, which are the only types of resources available.
33   * Property files can inherit properties from other files so that
34   * a base property file can be used and a small number of properties
35   * can be over-ridden by another property file. For example you may
36   * create an english version of a resource file named "resource.properties".
37   * You then decide that the British English version of all of the properties
38   * except one are the same, so there is no need to redefine all of the
39   * properties in "resource_en_GB", just the one that is different.</p>
40   * <p>The basename is the name of the property file without the ".properties"
41   * extension.</p>
42   * <p>Properties will be cached for performance.<p>
43   * <p>Property values stored in the property files can also contain dynamic
44   * variables. Any dynamic variable defined in PropertiesUtil.getVariableValue()
45   * can be used (such as {date}), as well as arguments in the form {0}, {1}, etc.
46   * Argument values are specified in the various overloaded getString() methods.</p>
47   * 
48   * @author Richard A. Sitze (rsitze@us.ibm.com)
49   * @author Karl Moss (kmoss@macromedia.com)
50   * @author Glen Daniels (gdaniels@apache.org)
51   */
52  public class ProjectResourceBundle extends ResourceBundle {
53      protected static Log log =
54          LogFactory.getLog(ProjectResourceBundle.class.getName());
55  
56  
57      // The static cache of ResourceBundles.
58      // The key is the 'basename + locale + default locale'
59      // The element is a ResourceBundle object
60      private static final Hashtable bundleCache = new Hashtable();
61  
62      private static final Locale defaultLocale = Locale.getDefault();
63  
64      private final ResourceBundle resourceBundle;
65      private final String resourceName;
66  
67      
68      protected Object handleGetObject(String key)
69          throws MissingResourceException
70      {
71          if (log.isDebugEnabled()) {
72              log.debug(this.toString() + "::handleGetObject(" + key + ")");
73          }
74  //            return resourceBundle.handleGetObject(key);
75          Object obj;
76          try {
77              obj = resourceBundle.getObject(key);
78          } catch (MissingResourceException e) {
79              /* catch missing resource, ignore, & return null
80               * if this method doesn't return null, then parents
81               * are not searched
82               */
83              obj = null;
84          }
85          return obj;
86      }
87      
88      public Enumeration getKeys() {
89          Enumeration myKeys = resourceBundle.getKeys();
90          if (parent == null) {
91              return myKeys;
92          } else {
93              final HashSet set = new HashSet();
94              while (myKeys.hasMoreElements()) {
95                  set.add(myKeys.nextElement());
96              }
97              
98              Enumeration pKeys = parent.getKeys();
99              while (pKeys.hasMoreElements()) {
100                 set.add(pKeys.nextElement());
101             }
102             
103             return new Enumeration() {
104                     private Iterator it = set.iterator();
105                     public boolean hasMoreElements() { return it.hasNext(); }
106                     public Object nextElement() { return it.next(); }
107                 };
108         }
109     }
110     
111 
112     /**
113      * Construct a new ProjectResourceBundle
114      * 
115      * @param projectName The name of the project to which the class belongs.
116      *        It must be a proper prefix of the caller's package.
117      * 
118      * @param caller The calling class.
119      *        This is used to get the package name to further construct
120      *        the basename as well as to get the proper ClassLoader.
121      * 
122      * @param resourceName The name of the resource without the
123      *        ".properties" extension
124      * 
125      * @throws MissingResourceException if projectName is not a prefix of
126      *         the caller's package name, or if the resource could not be
127      *         found/loaded.
128      */
129     public static ProjectResourceBundle getBundle(String projectName,
130                                                   String packageName,
131                                                   String resourceName)
132         throws MissingResourceException
133     {
134         return getBundle(projectName, packageName, resourceName, null, null, null);
135     }
136 
137     /**
138      * Construct a new ProjectResourceBundle
139      * 
140      * @param projectName The name of the project to which the class belongs.
141      *        It must be a proper prefix of the caller's package.
142      * 
143      * @param caller The calling class.
144      *        This is used to get the package name to further construct
145      *        the basename as well as to get the proper ClassLoader.
146      * 
147      * @param resourceName The name of the resource without the
148      *        ".properties" extension
149      * 
150      * @throws MissingResourceException if projectName is not a prefix of
151      *         the caller's package name, or if the resource could not be
152      *         found/loaded.
153      */
154     public static ProjectResourceBundle getBundle(String projectName,
155                                                   Class  caller,
156                                                   String resourceName,
157                                                   Locale locale)
158         throws MissingResourceException
159     {
160         return getBundle(projectName,
161                          caller,
162                          resourceName,
163                          locale,
164                          null);
165     }
166 
167     /**
168      * Construct a new ProjectResourceBundle
169      * 
170      * @param projectName The name of the project to which the class belongs.
171      *        It must be a proper prefix of the caller's package.
172      * 
173      * @param caller The calling class.
174      *        This is used to get the package name to further construct
175      *        the basename as well as to get the proper ClassLoader.
176      * 
177      * @param resourceName The name of the resource without the
178      *        ".properties" extension
179      * 
180      * @param locale The locale
181      * 
182      * @throws MissingResourceException if projectName is not a prefix of
183      *         the caller's package name, or if the resource could not be
184      *         found/loaded.
185      */
186     public static ProjectResourceBundle getBundle(String projectName,
187                                                   String packageName,
188                                                   String resourceName,
189                                                   Locale locale,
190                                                   ClassLoader loader)
191         throws MissingResourceException
192     {
193         return getBundle(projectName, packageName, resourceName, locale, loader, null);
194     }
195 
196     /**
197      * Construct a new ProjectResourceBundle
198      * 
199      * @param projectName The name of the project to which the class belongs.
200      *        It must be a proper prefix of the caller's package.
201      * 
202      * @param caller The calling class.
203      *        This is used to get the package name to further construct
204      *        the basename as well as to get the proper ClassLoader.
205      * 
206      * @param resourceName The name of the resource without the
207      *        ".properties" extension
208      * 
209      * @param locale The locale
210      * 
211      * @param extendsBundle If non-null, then this ExtendMessages will
212      *         default to extendsBundle.
213      * 
214      * @throws MissingResourceException if projectName is not a prefix of
215      *         the caller's package name, or if the resource could not be
216      *         found/loaded.
217      */
218     public static ProjectResourceBundle getBundle(String projectName,
219                                                   Class  caller,
220                                                   String resourceName,
221                                                   Locale locale,
222                                                   ResourceBundle extendsBundle)
223         throws MissingResourceException
224     {
225         return getBundle(projectName,
226                          getPackage(caller.getClass().getName()),
227                          resourceName,
228                          locale,
229                          caller.getClass().getClassLoader(),
230                          extendsBundle);
231     }
232 
233     /**
234      * Construct a new ProjectResourceBundle
235      * 
236      * @param projectName The name of the project to which the class belongs.
237      *        It must be a proper prefix of the caller's package.
238      * 
239      * @param caller The calling class.
240      *        This is used to get the package name to further construct
241      *        the basename as well as to get the proper ClassLoader.
242      * 
243      * @param resourceName The name of the resource without the
244      *        ".properties" extension
245      * 
246      * @param locale The locale
247      * 
248      * @param extendsBundle If non-null, then this ExtendMessages will
249      *         default to extendsBundle.
250      * 
251      * @throws MissingResourceException if projectName is not a prefix of
252      *         the caller's package name, or if the resource could not be
253      *         found/loaded.
254      */
255     public static ProjectResourceBundle getBundle(String projectName,
256                                                   String packageName,
257                                                   String resourceName,
258                                                   Locale locale,
259                                                   ClassLoader loader,
260                                                   ResourceBundle extendsBundle)
261         throws MissingResourceException
262     {
263         if (log.isDebugEnabled()) {
264             log.debug("getBundle(" + projectName + ","
265                                    + packageName + ","
266                                    + resourceName + ","
267                                    + String.valueOf(locale) + ",...)");
268         }
269         
270         Context context = new Context();
271         context.setLocale(locale);
272         context.setLoader(loader);
273         context.setProjectName(projectName);
274         context.setResourceName(resourceName);
275         context.setParentBundle(extendsBundle);
276 
277         packageName = context.validate(packageName);
278 
279         ProjectResourceBundle bundle = null;
280         try {
281             bundle = getBundle(context, packageName);
282         } catch (RuntimeException e) {
283             log.debug("Exception: ", e);
284             throw e;
285         }
286         
287         if (bundle == null) {
288             throw new MissingResourceException("Cannot find resource '" +
289                                                packageName + '.' + resourceName + "'",
290                                                resourceName, "");
291         }
292         
293         return bundle;
294     }
295 
296     /**
297      * get bundle...
298      * - check cache
299      * - try up hierarchy
300      * - if at top of hierarchy, use (link to) context.getParentBundle()
301      */
302     private static synchronized ProjectResourceBundle getBundle(Context context, String packageName)
303         throws MissingResourceException
304     {
305         String cacheKey = context.getCacheKey(packageName);
306         
307         ProjectResourceBundle prb = (ProjectResourceBundle)bundleCache.get(cacheKey);
308 
309         if (prb == null) {
310             String name = packageName + '.' + context.getResourceName();
311             ResourceBundle rb = context.loadBundle(packageName);
312             ResourceBundle parent = context.getParentBundle(packageName);
313             
314             if (rb != null) {
315                 prb = new ProjectResourceBundle(name, rb);
316                 prb.setParent(parent);
317                 if (log.isDebugEnabled()) {
318                     log.debug("Created " + prb + ", linked to parent " + String.valueOf(parent));
319                 }
320             } else {
321                 if (parent != null) {
322                     if (parent instanceof ProjectResourceBundle) {
323                         prb = (ProjectResourceBundle)parent;
324                     } else {
325                         prb = new ProjectResourceBundle(name, parent);
326                     }
327                     if (log.isDebugEnabled()) {
328                         log.debug("Root package not found, cross link to " + parent);
329                     }
330                 }
331             }
332 
333             if (prb != null) {
334                 // Cache the resource
335                 bundleCache.put(cacheKey, prb);
336             }
337         }
338 
339         return prb;
340     }
341 
342     private static final String getPackage(String name) {
343         return name.substring(0, name.lastIndexOf('.')).intern();
344     }
345     
346     /**
347       * Construct a new ProjectResourceBundle
348       */
349     private ProjectResourceBundle(String name, ResourceBundle bundle)
350         throws MissingResourceException
351     {
352         this.resourceBundle = bundle;
353         this.resourceName = name;
354     }
355     
356     public String getResourceName() {
357         return resourceName;
358     }
359 
360     /**
361      * Clears the internal cache
362      */
363     public static void clearCache()
364     {
365         bundleCache.clear();
366     }
367     
368     public String toString() {
369         return resourceName;
370     }
371 
372 
373     private static class Context {
374         private Locale _locale;
375         private ClassLoader _loader;
376         private String _projectName;
377         private String _resourceName;
378         private ResourceBundle _parent;
379         
380         void setLocale(Locale l) {
381             /* 1. Docs indicate that if locale is not specified,
382              *    then the default local is used in it's place.
383              * 2. A null value for locale is invalid.
384              * 
385              * Therefore, default...
386              */
387             _locale = (l == null) ? defaultLocale : l;
388         }
389 
390         void setLoader(ClassLoader l) {
391             _loader = (l != null) ? l : this.getClass().getClassLoader();
392             // START FIX: http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16868
393             if (_loader == null) {
394                 _loader = ClassLoader.getSystemClassLoader();
395             }
396             // END FIX: http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16868
397         }
398         
399         void setProjectName(String name) { _projectName = name.intern(); }
400         void setResourceName(String name) { _resourceName = name.intern(); }
401         void setParentBundle(ResourceBundle b) { _parent = b; }
402         
403         Locale getLocale() { return _locale; }
404         ClassLoader getLoader() { return _loader; }
405         String getProjectName() { return _projectName; }
406         String getResourceName() { return _resourceName; }
407         ResourceBundle getParentBundle() { return _parent; }
408     
409         String getCacheKey(String packageName)
410         {
411             String loaderName = (_loader == null) ? "" : (":" + _loader.hashCode());
412             return packageName + "." + _resourceName + ":" + _locale + ":" + defaultLocale + loaderName;
413         }
414 
415         ResourceBundle loadBundle(String packageName)
416         {
417             try {
418                 return ResourceBundle.getBundle(packageName + '.' + _resourceName,
419                                                 _locale,
420                                                 _loader);
421             } catch (MissingResourceException e) {
422                 // Deliberately surpressing print stack.. just the string for info.
423                 log.debug("loadBundle: Ignoring MissingResourceException: " + e.getMessage());
424             }
425             return null;
426         }
427     
428         ResourceBundle getParentBundle(String packageName)
429         {
430             ResourceBundle p;
431             if (packageName != _projectName) {
432                 p = getBundle(this, getPackage(packageName));
433             } else {
434                 p = _parent;
435                 _parent = null;
436             }
437             return p;
438         }
439         
440         String validate(String packageName)
441             throws MissingResourceException
442         {
443             if (_projectName == null  ||  _projectName.length() == 0) {
444                 log.debug("Project name not specified");
445                 throw new MissingResourceException("Project name not specified",
446                                                    "", "");
447             }
448 
449             if (packageName == null  ||  packageName.length() == 0) {
450                 log.debug("Package name not specified");
451                 throw new MissingResourceException("Package not specified",
452                                                    packageName, "");
453             }
454             packageName = packageName.intern();
455     
456             /* Ensure that project is a proper prefix of class.
457              * Terminate project name with '.' to ensure proper match.
458              */
459             if (packageName != _projectName  &&  !packageName.startsWith(_projectName + '.')) {
460                 log.debug("Project not a prefix of Package");
461                 throw new MissingResourceException("Project '" + _projectName
462                                  + "' must be a prefix of Package '"
463                                  + packageName + "'",
464                                  packageName + '.' + _resourceName, "");
465             }
466                 
467             return packageName;
468         }
469     }
470 }