KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > icu > impl > ICUResourceBundle


1 //##header 1189099963000 FOUNDATION
2
/*
3  * *****************************************************************************
4  * Copyright (C) 2005-2006, International Business Machines Corporation and * others.
5  * All Rights Reserved. *
6  * *****************************************************************************
7  */

8
9 package com.ibm.icu.impl;
10
11 import java.io.BufferedReader JavaDoc;
12 import java.io.InputStream JavaDoc;
13 import java.io.InputStreamReader JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.lang.ref.SoftReference JavaDoc;
16 import java.net.URL JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.Arrays JavaDoc;
19 import java.util.Collections JavaDoc;
20 import java.util.Enumeration JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Locale JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.MissingResourceException JavaDoc;
26 import java.util.Set JavaDoc;
27 import java.util.Vector JavaDoc;
28
29 //#ifndef FOUNDATION
30
//##import java.nio.ByteBuffer;
31
//#else
32
import com.ibm.icu.impl.ByteBuffer;
33 //#endif
34
import com.ibm.icu.impl.URLHandler.URLVisitor;
35 import com.ibm.icu.util.StringTokenizer;
36 import com.ibm.icu.util.ULocale;
37 import com.ibm.icu.util.UResourceBundle;
38 import com.ibm.icu.util.UResourceTypeMismatchException;
39 import com.ibm.icu.util.VersionInfo;
40
41 public abstract class ICUResourceBundle extends UResourceBundle {
42     /**
43      * The data path to be used with getBundleInstance API
44      * @draft ICU 3.0
45      */

46     protected static final String JavaDoc ICU_DATA_PATH = "com/ibm/icu/impl/";
47     /**
48      * The data path to be used with getBundleInstance API
49      * @draft ICU 3.0
50      */

51     public static final String JavaDoc ICU_BUNDLE = "data/icudt" + VersionInfo.ICU_DATA_VERSION;
52
53     /**
54      * The base name of ICU data to be used with getBundleInstance API
55      * @draft ICU 3.0
56      */

57     public static final String JavaDoc ICU_BASE_NAME = ICU_DATA_PATH + ICU_BUNDLE;
58
59     /**
60      * The base name of collation data to be used with getBundleInstance API
61      * @draft ICU 3.0
62      */

63     public static final String JavaDoc ICU_COLLATION_BASE_NAME = ICU_BASE_NAME + "/coll";
64     
65     /**
66      * The base name of rbbi data to be used with getData API
67      * @draft ICU 3.6
68      */

69     public static final String JavaDoc ICU_BRKITR_NAME = "/brkitr";
70     
71     /**
72      * The base name of rbbi data to be used with getBundleInstance API
73      * @draft ICU 3.6
74      */

75     public static final String JavaDoc ICU_BRKITR_BASE_NAME = ICU_BASE_NAME + ICU_BRKITR_NAME;
76     
77     /**
78      * The base name of rbnf data to be used with getBundleInstance API
79      * @draft ICU 3.0
80      */

81     public static final String JavaDoc ICU_RBNF_BASE_NAME = ICU_BASE_NAME + "/rbnf";
82
83     /**
84      * The base name of transliterator data to be used with getBundleInstance API
85      * @draft ICU 3.0
86      */

87     public static final String JavaDoc ICU_TRANSLIT_BASE_NAME = ICU_BASE_NAME + "/translit";
88
89     /**
90      * The class loader constant to be used with getBundleInstance API
91      * @draft ICU 3.0
92      */

93     public static final ClassLoader JavaDoc ICU_DATA_CLASS_LOADER;
94     static {
95         ClassLoader JavaDoc loader = ICUData.class.getClassLoader();
96         if (loader == null) { // boot class loader
97
loader = ClassLoader.getSystemClassLoader();
98         }
99         ICU_DATA_CLASS_LOADER = loader;
100     }
101
102     /**
103      * The name of the resource containing the installed locales
104      * @draft ICU 3.0
105      */

106     protected static final String JavaDoc INSTALLED_LOCALES = "InstalledLocales";
107
108     /**
109      * Resource type constant for "no resource".
110      * @draft ICU 3.0
111      */

112     public static final int NONE = -1;
113
114     /**
115      * Resource type constant for strings.
116      * @draft ICU 3.0
117      */

118     public static final int STRING = 0;
119
120     /**
121      * Resource type constant for binary data.
122      * @draft ICU 3.0
123      */

124     public static final int BINARY = 1;
125
126     /**
127      * Resource type constant for tables of key-value pairs.
128      * @draft ICU 3.0
129      */

130     public static final int TABLE = 2;
131
132     /**
133      * Resource type constant for aliases;
134      * internally stores a string which identifies the actual resource
135      * storing the data (can be in a different resource bundle).
136      * Resolved internally before delivering the actual resource through the API.
137      * @draft ICU 3.0
138      * @internal
139      */

140     protected static final int ALIAS = 3;
141
142     /**
143      * Internal use only.
144      * Alternative resource type constant for tables of key-value pairs.
145      * Never returned by getType().
146      * @internal
147      * @draft ICU 3.0
148      */

149     protected static final int TABLE32 = 4;
150
151     /**
152      * Resource type constant for a single 28-bit integer, interpreted as
153      * signed or unsigned by the getInt() function.
154      * @see #getInt
155      * @draft ICU 3.0
156      */

157     public static final int INT = 7;
158
159     /**
160      * Resource type constant for arrays of resources.
161      * @draft ICU 3.0
162      */

163     public static final int ARRAY = 8;
164
165     /**
166      * Resource type constant for vectors of 32-bit integers.
167      * @see #getIntVector
168      * @draft ICU 3.0
169      */

170     public static final int INT_VECTOR = 14;
171
172     public static final int FROM_FALLBACK = 1, FROM_ROOT = 2, FROM_DEFAULT = 3, FROM_LOCALE = 4;
173
174     private int loadingStatus = -1;
175
176     public void setLoadingStatus(int newStatus) {
177         loadingStatus = newStatus;
178     }
179     /**
180      * Returns the loading status of a particular resource.
181      *
182      * @return FROM_FALLBACK if the resource is fetched from fallback bundle
183      * FROM_ROOT if the resource is fetched from root bundle.
184      * FROM_DEFAULT if the resource is fetched from the default locale.
185      */

186     public int getLoadingStatus() {
187         return loadingStatus;
188     }
189
190     /**
191      * Get the noFallback flag specified in the loaded bundle.
192      * @return The noFallback flag.
193      */

194     protected boolean getNoFallback() {
195         return false;
196     }
197
198     /**
199      * Return the version number associated with this UResourceBundle as an
200      * VersionInfo object.
201      * @return VersionInfo object containing the version of the bundle
202      * @draft ICU 3.0
203      */

204     public VersionInfo getVersion() {
205         return null;
206     }
207
208     /**
209      * Returns a string from a string resource type
210      *
211      * @return a string
212      * @see #getBinary()
213      * @see #getIntVector
214      * @see #getInt
215      * @throws MissingResourceException
216      * @throws UResourceTypeMismatchException
217      * @draft ICU 3.0
218      */

219     public String JavaDoc getString() {
220         throw new UResourceTypeMismatchException("");
221     }
222
223     /**
224      * @internal ICU 3.0
225      */

226     public String JavaDoc[] getStringArray() {
227         throw new UResourceTypeMismatchException("");
228     }
229
230     /*
231      * Returns a string from a string resource type
232      * @param key The key whose values needs to be fetched
233      * @return a string
234      * @see #getBinary
235      * @see #getIntVector
236      * @see #getInt
237      * @throws MissingResourceException
238      * @throws UResourceTypeMismatchException
239      * @draft ICU 3.0
240      */

241     // public String getString(String key) {
242
// throw new UResourceTypeMismatchException("");
243
// }
244

245     /**
246      * Returns a binary data from a binary resource.
247      *
248      * @return a pointer to a chuck of unsigned bytes which live in a memory mapped/DLL file.
249      * @see #getIntVector
250      * @see #getInt
251      * @throws MissingResourceException
252      * @throws UResourceTypeMismatchException
253      * @draft ICU 3.0
254      */

255     public ByteBuffer getBinary() {
256         throw new UResourceTypeMismatchException("");
257     }
258
259     /**
260      * Returns a binary data from a binary resource.
261      *
262      * @param ba Establish the return type from this function. The value of the parameter
263      * is not used; a null variable is OK. The thing that matters is the type
264      * of the parameter
265      * @return an array unsigned bytes containing the binary data from the resource.
266      * @see #getIntVector
267      * @see #getInt
268      * @throws MissingResourceException
269      * @throws UResourceTypeMismatchException
270      * @draft ICU 3.6
271      */

272     public byte [] getBinary(byte []ba) {
273         throw new UResourceTypeMismatchException("");
274     }
275     
276     /**
277      * Returns a 32 bit integer array from a resource.
278      *
279      * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL file.
280      * @see #getBinary()
281      * @see #getInt
282      * @throws MissingResourceException
283      * @throws UResourceTypeMismatchException
284      * @draft ICU 3.0
285      */

286     public int[] getIntVector() {
287         throw new UResourceTypeMismatchException("");
288     }
289
290     /**
291      * Returns a signed integer from a resource.
292      *
293      * @return an integer value
294      * @see #getIntVector
295      * @see #getBinary()
296      * @throws MissingResourceException
297      * @throws UResourceTypeMismatchException
298      * @stable ICU 2.0
299      */

300     public int getInt() {
301         throw new UResourceTypeMismatchException("");
302     }
303
304     /**
305      * Returns a unsigned integer from a resource.
306      * This integer is originally 28 bit and the sign gets propagated.
307      *
308      * @return an integer value
309      * @see #getIntVector
310      * @see #getBinary()
311      * @throws MissingResourceException
312      * @throws UResourceTypeMismatchException
313      * @stable ICU 2.0
314      */

315     public int getUInt() {
316         throw new UResourceTypeMismatchException("");
317     }
318     /**
319      * Returns the size of a resource. Size for scalar types is always 1,
320      * and for vector/table types is the number of child resources.
321      * <br><b><font color='red'>Warning: </font></b> Integer array is treated as a scalar type. There are no
322      * APIs to access individual members of an integer array. It
323      * is always returned as a whole.
324      * @return number of resources in a given resource.
325      * @draft ICU 3.0
326      */

327     public int getSize() {
328         return size;
329     }
330
331     /**
332      * Returns the type of a resource.
333      * Available types are {@link #INT INT}, {@link #ARRAY ARRAY},
334      * {@link #BINARY BINARY}, {@link #INT_VECTOR INT_VECTOR},
335      * {@link #STRING STRING}, {@link #TABLE TABLE}.
336      *
337      * @return type of the given resource.
338      * @draft ICU 3.0
339      */

340     public int getType() {
341         int type = ICUResourceBundleImpl.RES_GET_TYPE(resource);
342         if(type==TABLE32){
343             return TABLE; //Mask the table32's real type
344
}
345         return type;
346     }
347
348     /**
349      * Returns the key associated with a given resource. Not all the resources have a key - only
350      * those that are members of a table.
351      * @return a key associated to this resource, or NULL if it doesn't have a key
352      * @draft ICU 3.0
353      */

354     public String JavaDoc getKey() {
355         return key;
356     }
357
358     /**
359      * Returns the iterator which iterates over this
360      * resource bundle
361      * @draft ICU 3.0
362      */

363     public ICUResourceBundleIterator getIterator() {
364         return new ICUResourceBundleIterator(this);
365     }
366
367     /**
368      * Returns the resource in a given resource at the specified index.
369      *
370      * @param index an index to the wanted resource.
371      * @return the sub resource UResourceBundle object
372      * @throws IndexOutOfBoundsException
373      * @draft ICU 3.0
374      */

375     public ICUResourceBundle get(int index) {
376         return getImpl(index, null, this);
377     }
378     protected ICUResourceBundle getImpl(int index, HashMap JavaDoc table,
379             ICUResourceBundle requested) {
380         ICUResourceBundle obj = handleGet(index, table, requested);
381         if (obj == null) {
382             obj = (ICUResourceBundle) getParent();
383             if (obj != null) {
384                 obj = obj.getImpl(index, table, requested);
385             }
386             if (obj == null)
387                 throw new MissingResourceException JavaDoc(
388                         "Can't find resource for bundle "
389                                 + this.getClass().getName() + ", key "
390                                 + getKey(), this.getClass().getName(), getKey());
391         }
392         setLoadingStatus(obj, requested.getLocaleID());
393         return obj;
394     }
395     // abstract UResourceBundle handleGetInt(int index);
396

397     /**
398      * Returns a resource in a given resource that has a given key.
399      *
400      * @param key a key associated with the wanted resource
401      * @return a resource bundle object representing rhe resource
402      * @throws MissingResourceException
403      * @draft ICU 3.0
404      */

405     public ICUResourceBundle get(String JavaDoc key) {
406         return getImpl(key, null, this);
407     }
408     protected ICUResourceBundle getImpl(String JavaDoc key, HashMap JavaDoc table,
409             ICUResourceBundle requested) {
410         ICUResourceBundle obj = handleGet(key, table, requested);
411         if (obj == null) {
412             obj = (ICUResourceBundle) getParent();
413             if (obj != null) {
414                 //call the get method to recursively fetch the resource
415
obj = obj.getImpl(key, table, requested);
416             }
417             if (obj == null) {
418                 String JavaDoc fullName = ICUResourceBundleReader.getFullName(
419                         getBaseName(), getLocaleID());
420                 throw new MissingResourceException JavaDoc(
421                         "Can't find resource for bundle " + fullName + ", key "
422                                 + key, this.getClass().getName(), key);
423             }
424         }
425         setLoadingStatus(obj, requested.getLocaleID());
426         return obj;
427     }
428
429     private static void setLoadingStatus(ICUResourceBundle bundle, String JavaDoc requestedLocale){
430        String JavaDoc locale = bundle.getLocaleID();
431        if(locale.equals("root")){
432            bundle.setLoadingStatus(FROM_ROOT);
433            return;
434        }
435        if(locale.equals(requestedLocale)){
436            bundle.setLoadingStatus(FROM_LOCALE);
437        }else{
438            bundle.setLoadingStatus(FROM_FALLBACK);
439        }
440     }
441     
442     /**
443      * Returns the string in a given resource at the specified index.
444      *
445      * @param index an index to the wanted string.
446      * @return a string which lives in the resource.
447      * @throws IndexOutOfBoundsException
448      * @throws UResourceTypeMismatchException
449      * @draft ICU 3.0
450      */

451     public String JavaDoc getString(int index) {
452         ICUResourceBundle temp = get(index);
453         if (temp.getType() == STRING) {
454             return temp.getString();
455         }
456         throw new UResourceTypeMismatchException("");
457     }
458
459     /**
460      * Returns the parent bundle of this bundle
461      * @return UResourceBundle the parent of this bundle. Returns null if none
462      * @draft ICU 3.0
463      */

464     public abstract UResourceBundle getParent();
465
466     /**
467      * Returns the locale id of this bundle as String
468      * @return String locale id
469      * @draft ICU 3.4
470      */

471     protected abstract String JavaDoc getLocaleID();
472
473     /**
474      * Returns a functionally equivalent locale, considering keywords as well, for the specified keyword.
475      * @param baseName resource specifier
476      * @param resName top level resource to consider (such as "collations")
477      * @param keyword a particular keyword to consider (such as "collation" )
478      * @param locID The requested locale
479      * @param fillinIsAvailable If non-null, 1-element array of fillin parameter that indicates whether the
480      * requested locale was available. The locale is defined as 'available' if it physically
481      * exists within the specified tree.
482      * @return the locale
483      * @internal ICU 3.0
484      */

485     public static final ULocale getFunctionalEquivalent(String JavaDoc baseName,
486             String JavaDoc resName, String JavaDoc keyword, ULocale locID,
487             boolean fillinIsAvailable[]) {
488         String JavaDoc kwVal = locID.getKeywordValue(keyword);
489         String JavaDoc baseLoc = locID.getBaseName();
490         String JavaDoc defStr = null;
491         ULocale parent = new ULocale(baseLoc);
492         ULocale found = locID;
493         ULocale defLoc = null; // locale where default (found) resource is
494
boolean lookForDefault = false; // true if kwVal needs to be set
495
ULocale fullBase = null; // base locale of found (target) resource
496
int defDepth = 0; // depth of 'default' marker
497
int resDepth = 0; // depth of found resource;
498
if (fillinIsAvailable != null) {
499             fillinIsAvailable[0] = true;
500         }
501
502         if ((kwVal == null) || (kwVal.length() == 0)
503                 || kwVal.equals(DEFAULT_TAG)) {
504             kwVal = ""; // default tag is treated as no keyword
505
lookForDefault = true;
506         }
507
508         // Check top level locale first
509
ICUResourceBundle r = null;
510
511         r = (ICUResourceBundle) UResourceBundle.getBundleInstance(baseName, parent);
512         found = r.getULocale();
513         if (fillinIsAvailable != null) {
514             if (!found.equals(parent)) {
515                 fillinIsAvailable[0] = false;
516             }
517         }
518         // determine in which locale (if any) the currently relevant 'default' is
519
do {
520             try {
521                 ICUResourceBundle irb = r.get(resName);
522                 defStr = irb.getString(DEFAULT_TAG);
523                 if (lookForDefault == true) {
524                     kwVal = defStr;
525                     lookForDefault = false;
526                 }
527                 defLoc = r.getULocale();
528             } catch (MissingResourceException JavaDoc t) {
529                 // Ignore error and continue search.
530
}
531             if (defLoc == null) {
532                 r = (ICUResourceBundle) r.getParent();
533                 defDepth++;
534             }
535         } while ((r != null) && (defLoc == null));
536
537         // Now, search for the named resource
538
parent = new ULocale(baseLoc);
539         r = (ICUResourceBundle) UResourceBundle.getBundleInstance(baseName, parent);
540         // determine in which locale (if any) the named resource is located
541
do {
542             try {
543                 ICUResourceBundle irb = r.get(resName);
544                 /* UResourceBundle urb = */irb.get(kwVal);
545                 fullBase = irb.getULocale();
546                 // If the get() completed, we have the full base locale
547
// If we fell back to an ancestor of the old 'default',
548
// we need to re calculate the "default" keyword.
549
if ((fullBase != null) && ((resDepth) > defDepth)) {
550                     defStr = irb.getString(DEFAULT_TAG);
551                     defLoc = r.getULocale();
552                     defDepth = resDepth;
553                 }
554             } catch (MissingResourceException JavaDoc t) {
555                 // Ignore error,
556
}
557             if (fullBase == null) {
558                 r = (ICUResourceBundle) r.getParent();
559                 resDepth++;
560             }
561         } while ((r != null) && (fullBase == null));
562
563         if (fullBase == null && // Could not find resource 'kwVal'
564
(defStr != null) && // default was defined
565
!defStr.equals(kwVal)) { // kwVal is not default
566
// couldn't find requested resource. Fall back to default.
567
kwVal = defStr; // Fall back to default.
568
parent = new ULocale(baseLoc);
569             r = (ICUResourceBundle) UResourceBundle.getBundleInstance(baseName, parent);
570             resDepth = 0;
571             // determine in which locale (if any) the named resource is located
572
do {
573                 try {
574                     ICUResourceBundle irb = r.get(resName);
575                     UResourceBundle urb = irb.get(kwVal);
576                     
577                     // if we didn't fail before this..
578
fullBase = r.getULocale();
579                     
580                     // If the fetched item (urb) is in a different locale than our outer locale (r/fullBase)
581
// then we are in a 'fallback' situation. treat as a missing resource situation.
582
if(!fullBase.toString().equals(urb.getLocale().toString())) {
583                         fullBase = null; // fallback condition. Loop and try again.
584
}
585
586                     // If we fell back to an ancestor of the old 'default',
587
// we need to re calculate the "default" keyword.
588
if ((fullBase != null) && ((resDepth) > defDepth)) {
589                         defStr = irb.getString(DEFAULT_TAG);
590                         defLoc = r.getULocale();
591                         defDepth = resDepth;
592                     }
593                 } catch (MissingResourceException JavaDoc t) {
594                     // Ignore error, continue search.
595
}
596                 if (fullBase == null) {
597                     r = (ICUResourceBundle) r.getParent();
598                     resDepth++;
599                 }
600             } while ((r != null) && (fullBase == null));
601         }
602
603         if (fullBase == null) {
604             throw new MissingResourceException JavaDoc(
605                 "Could not find locale containing requested or default keyword.",
606                 baseName, keyword + "=" + kwVal);
607         }
608
609         if (defStr.equals(kwVal) // if default was requested and
610
&& resDepth <= defDepth) { // default was set in same locale or child
611
return fullBase; // Keyword value is default - no keyword needed in locale
612
} else {
613             return new ULocale(fullBase.toString() + "@" + keyword + "=" + kwVal);
614         }
615     }
616
617     /**
618      * Given a tree path and keyword, return a string enumeration of all possible values for that keyword.
619      * @param baseName resource specifier
620      * @param keyword a particular keyword to consider, must match a top level resource name
621      * within the tree. (i.e. "collations")
622      * @internal ICU 3.0
623      */

624     public static final String JavaDoc[] getKeywordValues(String JavaDoc baseName, String JavaDoc keyword) {
625         Set JavaDoc keywords = new HashSet JavaDoc();
626         ULocale locales[] = createULocaleList(baseName, ICU_DATA_CLASS_LOADER);
627         int i;
628
629         for (i = 0; i < locales.length; i++) {
630             try {
631                 UResourceBundle b = UResourceBundle.getBundleInstance(baseName, locales[i]);
632                 // downcast to ICUResourceBundle?
633
ICUResourceBundle irb = (ICUResourceBundle) (b.getObject(keyword));
634                 Enumeration JavaDoc e = irb.getKeys();
635                 Object JavaDoc s;
636                 while (e.hasMoreElements()) {
637                     s = e.nextElement();
638                     if ((s instanceof String JavaDoc) && !DEFAULT_TAG.equals(s)) {
639                         // don't add 'default' items
640
keywords.add(s);
641                     }
642                 }
643             } catch (Throwable JavaDoc t) {
644                 //System.err.println("Error in - " + new Integer(i).toString()
645
// + " - " + t.toString());
646
// ignore the err - just skip that resource
647
}
648         }
649         return (String JavaDoc[])keywords.toArray(new String JavaDoc[0]);
650     }
651
652     /**
653      * This method performs multilevel fallback for fetching items from the
654      * bundle e.g: If resource is in the form de__PHONEBOOK{ collations{
655      * default{ "phonebook"} } } If the value of "default" key needs to be
656      * accessed, then do: <code>
657      * UResourceBundle bundle = UResourceBundle.getBundleInstance("de__PHONEBOOK");
658      * ICUResourceBundle result = null;
659      * if(bundle instanceof ICUResourceBundle){
660      * result = ((ICUResourceBundle) bundle).getWithFallback("collations/default");
661      * }
662      * </code>
663      *
664      * @param path
665      * The path to the required resource key
666      * @return resource represented by the key
667      * @exception MissingResourceException
668      */

669     public ICUResourceBundle getWithFallback(String JavaDoc path)
670             throws MissingResourceException JavaDoc {
671         ICUResourceBundle result = null;
672         ICUResourceBundle actualBundle = this;
673
674         // now recuse to pick up sub levels of the items
675
result = findResourceWithFallback(path, actualBundle, null);
676
677         if (result == null) {
678             throw new MissingResourceException JavaDoc(
679                 "Can't find resource for bundle "
680                 + this.getClass().getName() + ", key " + getType(),
681                 path, getKey());
682         }
683         return result;
684     }
685
686     // will throw type mismatch exception if the resource is not a string
687
public String JavaDoc getStringWithFallback(String JavaDoc path) throws MissingResourceException JavaDoc {
688         return getWithFallback(path).getString();
689     }
690
691     /**
692      * Return a set of the locale names supported by a collection of resource
693      * bundles.
694      *
695      * @param bundlePrefix the prefix of the resource bundles to use.
696      */

697     public static Set JavaDoc getAvailableLocaleNameSet(String JavaDoc bundlePrefix) {
698         return getAvailEntry(bundlePrefix).getLocaleNameSet();
699     }
700
701     /**
702      * Return a set of all the locale names supported by a collection of
703      * resource bundles.
704      */

705     public static Set JavaDoc getFullLocaleNameSet() {
706         return getFullLocaleNameSet(ICU_BASE_NAME);
707     }
708
709     /**
710      * Return a set of all the locale names supported by a collection of
711      * resource bundles.
712      *
713      * @param bundlePrefix the prefix of the resource bundles to use.
714      */

715     public static Set JavaDoc getFullLocaleNameSet(String JavaDoc bundlePrefix) {
716         return getAvailEntry(bundlePrefix).getFullLocaleNameSet();
717     }
718
719     /**
720      * Return a set of the locale names supported by a collection of resource
721      * bundles.
722      */

723     public static Set JavaDoc getAvailableLocaleNameSet() {
724         return getAvailableLocaleNameSet(ICU_BASE_NAME);
725     }
726
727     /**
728      * Get the set of Locales installed in the specified bundles.
729      * @return the list of available locales
730      * @draft ICU 3.0
731      */

732     public static final ULocale[] getAvailableULocales(String JavaDoc baseName) {
733         return getAvailEntry(baseName).getULocaleList();
734     }
735
736     /**
737      * Get the set of ULocales installed the base bundle.
738      * @return the list of available locales
739      * @draft ICU 3.0
740      */

741     public static final ULocale[] getAvailableULocales() {
742         return getAvailableULocales(ICU_BASE_NAME);
743     }
744
745     /**
746      * Get the set of Locales installed in the specified bundles.
747      * @return the list of available locales
748      * @draft ICU 3.0
749      */

750     public static final Locale JavaDoc[] getAvailableLocales(String JavaDoc baseName) {
751         return getAvailEntry(baseName).getLocaleList();
752     }
753
754    /**
755      * Get the set of Locales installed the base bundle.
756      * @return the list of available locales
757      * @draft ICU 3.0
758      */

759     public static final Locale JavaDoc[] getAvailableLocales() {
760         return getAvailEntry(ICU_BASE_NAME).getLocaleList();
761     }
762
763     /**
764      * Convert a list of ULocales to a list of Locales. ULocales with a script code will not be converted
765      * since they cannot be represented as a Locale. This means that the two lists will <b>not</b> match
766      * one-to-one, and that the returned list might be shorter than the input list.
767      * @param ulocales a list of ULocales to convert to a list of Locales.
768      * @return the list of converted ULocales
769      * @draft ICU 3.0
770      */

771     public static final Locale JavaDoc[] getLocaleList(ULocale[] ulocales) {
772         ArrayList JavaDoc list = new ArrayList JavaDoc();
773         for (int i = 0; i < ulocales.length; i++) {
774             // if the ULocale does not contain a script code
775
// only then convert it to a Locale object
776
if (ulocales[i].getScript().length() == 0) {
777                 list.add(ulocales[i].toLocale());
778             }
779         }
780         return (Locale JavaDoc[]) list.toArray(new Locale JavaDoc[list.size()]);
781     }
782  
783     public Enumeration JavaDoc getKeys() {
784         initKeysVector();
785         return keys.elements();
786     }
787     private Vector JavaDoc keys = null;
788     private synchronized void initKeysVector(){
789         if(keys!=null){
790             return;
791         }
792         //ICUResourceBundle current = this;
793
keys = new Vector JavaDoc();
794         //while(current!=null){
795
Enumeration JavaDoc e = this.handleGetKeys();
796             while(e.hasMoreElements()){
797                 String JavaDoc elem = (String JavaDoc)e.nextElement();
798                 if(!keys.contains(elem)){
799                     keys.add(elem);
800                 }
801             }
802           // current = (ICUResourceBundle)current.getParent();
803
//}
804
}
805     protected Enumeration JavaDoc handleGetKeys(){
806         Vector JavaDoc keys = new Vector JavaDoc();
807         ICUResourceBundle item = null;
808         for (int i = 0; i < size; i++) {
809             item = get(i);
810             keys.add(item.getKey());
811         }
812         return keys.elements();
813     }
814
815     public static ICUResourceBundle createBundle(String JavaDoc baseName,
816             String JavaDoc localeID, ClassLoader JavaDoc root) {
817         ICUResourceBundle b = ICUResourceBundleImpl.createBundle(baseName, localeID, root);
818         if(b==null){
819             throw new MissingResourceException JavaDoc("Could not find the bundle "+ baseName+"/"+ localeID+".res","","");
820         }
821         return b;
822     }
823
824     //====== protected members ==============
825
protected String JavaDoc key;
826     protected int size = 1;
827     protected String JavaDoc resPath;
828     protected long resource = RES_BOGUS;
829     protected boolean isTopLevel = false;
830
831     protected static final long UNSIGNED_INT_MASK = 0xffffffffL;
832
833     protected static final long RES_BOGUS = 0xffffffff;
834
835     protected ICUResourceBundle handleGet(String JavaDoc key, HashMap JavaDoc table,
836             ICUResourceBundle requested) {
837         throw new UResourceTypeMismatchException("");
838     }
839     protected ICUResourceBundle handleGet(int index, HashMap JavaDoc table,
840             ICUResourceBundle requested) {
841         throw new UResourceTypeMismatchException("");
842     }
843
844     /**
845      * Returns the locale of this resource bundle. This method can be used after
846      * a call to getBundle() to determine whether the resource bundle returned
847      * really corresponds to the requested locale or is a fallback.
848      *
849      * @return the locale of this resource bundle
850      */

851     public Locale JavaDoc getLocale() {
852         return getULocale().toLocale();
853     }
854
855     // this method is declared in ResourceBundle class
856
// so cannot change the signature
857
protected Object JavaDoc handleGetObject(String JavaDoc key) {
858         return handleGetObjectImpl(key, this);
859     }
860
861     // To facilitate XPath style aliases we need a way to pass the reference
862
// to requested locale. The only way I could figure out is to implement
863
// the look up logic here. This has a disadvantage that if the client
864
// loads an ICUResourceBundle, calls ResourceBundle.getObject method
865
// with a key that does not exist in the bundle then the lookup is
866
// done twice before throwing a MissingResourceExpection.
867
private Object JavaDoc handleGetObjectImpl(String JavaDoc key, ICUResourceBundle requested) {
868         Object JavaDoc obj = resolveObject(key, requested);
869         if (obj == null) {
870             ICUResourceBundle parent = (ICUResourceBundle) getParent();
871             if (parent != null) {
872                 obj = parent.handleGetObjectImpl(key, requested);
873             }
874             if (obj == null)
875                 throw new MissingResourceException JavaDoc(
876                     "Can't find resource for bundle "
877                     + this.getClass().getName() + ", key " + key,
878                     this.getClass().getName(), key);
879         }
880         return obj;
881     }
882
883     private Object JavaDoc resolveObject(String JavaDoc key, ICUResourceBundle requested) {
884         if (getType() == STRING) {
885             return getString();
886         }
887         ICUResourceBundle obj = handleGet(key, requested);
888         if (obj != null) {
889             if (obj.getType() == STRING) {
890                 return obj.getString();
891             }
892             try {
893                 if (obj.getType() == ARRAY) {
894                     return obj.handleGetStringArray();
895                 }
896             } catch (UResourceTypeMismatchException ex) {
897                 return obj;
898             }
899         }
900         return obj;
901     }
902
903     protected ICUResourceBundle handleGet(int index, ICUResourceBundle requested) {
904         return null;
905     }
906
907     protected ICUResourceBundle handleGet(String JavaDoc key,
908             ICUResourceBundle requested) {
909         return null;
910     }
911
912     protected String JavaDoc[] handleGetStringArray() {
913         return null;
914     }
915
916     // ========== privates ==========
917
private static final String JavaDoc ICU_RESOURCE_INDEX = "res_index";
918
919     private static final String JavaDoc DEFAULT_TAG = "default";
920
921     // Flag for enabling/disabling debugging code
922
private static final boolean DEBUG = ICUDebug.enabled("localedata");
923
924     // Cache for getAvailableLocales
925
private static SoftReference JavaDoc GET_AVAILABLE_CACHE;
926     private static final ULocale[] createULocaleList(String JavaDoc baseName,
927             ClassLoader JavaDoc root) {
928         // the canned list is a subset of all the available .res files, the idea
929
// is we don't export them
930
// all. gotta be a better way to do this, since to add a locale you have
931
// to update this list,
932
// and it's embedded in our binary resources.
933
ICUResourceBundle bundle = (ICUResourceBundle) UResourceBundle.instantiateBundle(baseName, ICU_RESOURCE_INDEX, root, true);
934         
935         bundle = bundle.get(INSTALLED_LOCALES);
936         int length = bundle.getSize();
937         int i = 0;
938         ULocale[] locales = new ULocale[length];
939         ICUResourceBundleIterator iter = bundle.getIterator();
940         iter.reset();
941         while (iter.hasNext()) {
942             locales[i++] = new ULocale(iter.next().getKey());
943         }
944         bundle = null;
945         return locales;
946     }
947
948     private static final Locale JavaDoc[] createLocaleList(String JavaDoc baseName) {
949         ULocale[] ulocales = getAvailEntry(baseName).getULocaleList();
950         return getLocaleList(ulocales);
951     }
952
953     private static final String JavaDoc[] createLocaleNameArray(String JavaDoc baseName,
954             ClassLoader JavaDoc root) {
955         ICUResourceBundle bundle = (ICUResourceBundle) UResourceBundle.instantiateBundle( baseName, ICU_RESOURCE_INDEX, root, true);
956         bundle = bundle.get(INSTALLED_LOCALES);
957         int length = bundle.getSize();
958         int i = 0;
959         String JavaDoc[] locales = new String JavaDoc[length];
960         ICUResourceBundleIterator iter = bundle.getIterator();
961         iter.reset();
962         while (iter.hasNext()) {
963             locales[i++] = iter.next().getKey();
964         }
965         bundle = null;
966         return locales;
967     }
968
969     private static final ArrayList JavaDoc createFullLocaleNameArray(
970             final String JavaDoc baseName, final ClassLoader JavaDoc root) {
971
972         ArrayList JavaDoc list = (ArrayList JavaDoc) java.security.AccessController
973             .doPrivileged(new java.security.PrivilegedAction JavaDoc() {
974                 public Object JavaDoc run() {
975                     // WebSphere class loader will return null for a raw
976
// directory name without trailing slash
977
String JavaDoc bn = baseName.endsWith("/")
978                         ? baseName
979                         : baseName + "/";
980
981                     // look for prebuilt indices first
982
try {
983                         InputStream JavaDoc s = root.getResourceAsStream(bn + ICU_RESOURCE_INDEX + ".txt");
984                         if (s != null) {
985                             ArrayList JavaDoc list = new ArrayList JavaDoc();
986                             BufferedReader JavaDoc br = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(s, "ASCII"));
987                             String JavaDoc line;
988                             while ((line = br.readLine()) != null) {
989                                 if (line.length() != 0 && !line.startsWith("#")) {
990                                     list.add(line);
991                                 }
992                             }
993                             return list;
994                         }
995                     } catch (IOException JavaDoc e) {
996                         // swallow it
997
}
998
999                     URL JavaDoc url = root.getResource(bn);
1000                    URLHandler handler = URLHandler.get(url);
1001                    if (handler != null) {
1002                        final ArrayList JavaDoc list = new ArrayList JavaDoc();
1003                        URLVisitor v = new URLVisitor() {
1004                            public void visit(String JavaDoc s) {
1005                                if (s.endsWith(".res") && !"res_index.res".equals(s)) {
1006                                    list.add(s.substring(0, s.length() - 4)); // strip '.res'
1007
}
1008                            }
1009                        };
1010                        handler.guide(v, false);
1011                        return list;
1012                    }
1013
1014                    return null;
1015                }
1016            });
1017
1018        return list;
1019    }
1020
1021    private static Set JavaDoc createFullLocaleNameSet(String JavaDoc baseName) {
1022        ArrayList JavaDoc list = createFullLocaleNameArray(baseName,ICU_DATA_CLASS_LOADER);
1023        HashSet JavaDoc set = new HashSet JavaDoc();
1024        if(list==null){
1025            throw new MissingResourceException JavaDoc("Could not find "+ ICU_RESOURCE_INDEX, "", "");
1026        }
1027        set.addAll(list);
1028        return Collections.unmodifiableSet(set);
1029    }
1030
1031    private static Set JavaDoc createLocaleNameSet(String JavaDoc baseName) {
1032        try {
1033            String JavaDoc[] locales = createLocaleNameArray(baseName, ICU_DATA_CLASS_LOADER);
1034
1035            HashSet JavaDoc set = new HashSet JavaDoc();
1036            set.addAll(Arrays.asList(locales));
1037            return Collections.unmodifiableSet(set);
1038        } catch (MissingResourceException JavaDoc e) {
1039            if (DEBUG) {
1040                System.out.println("couldn't find index for bundleName: " + baseName);
1041                Thread.dumpStack();
1042            }
1043        }
1044        return Collections.EMPTY_SET;
1045    }
1046
1047    /**
1048     * Holds the prefix, and lazily creates the Locale[] list or the locale name
1049     * Set as needed.
1050     */

1051    private static final class AvailEntry {
1052        private String JavaDoc prefix;
1053        private ULocale[] ulocales;
1054        private Locale JavaDoc[] locales;
1055        private Set JavaDoc nameSet;
1056        private Set JavaDoc fullNameSet;
1057
1058        AvailEntry(String JavaDoc prefix) {
1059            this.prefix = prefix;
1060        }
1061
1062        ULocale[] getULocaleList() {
1063            if (ulocales == null) {
1064                ulocales = createULocaleList(prefix, ICU_DATA_CLASS_LOADER);
1065            }
1066            return ulocales;
1067        }
1068        Locale JavaDoc[] getLocaleList() {
1069            if (locales == null) {
1070                locales = createLocaleList(prefix);
1071            }
1072            return locales;
1073        }
1074        Set JavaDoc getLocaleNameSet() {
1075            if (nameSet == null) {
1076                nameSet = createLocaleNameSet(prefix);
1077            }
1078            return nameSet;
1079        }
1080        Set JavaDoc getFullLocaleNameSet() {
1081            if (fullNameSet == null) {
1082                fullNameSet = createFullLocaleNameSet(prefix);
1083            }
1084            return fullNameSet;
1085        }
1086    }
1087
1088    /**
1089     * Stores the locale information in a cache accessed by key (bundle prefix).
1090     * The cached objects are AvailEntries. The cache is held by a SoftReference
1091     * so it can be GC'd.
1092     */

1093    private static AvailEntry getAvailEntry(String JavaDoc key) {
1094        AvailEntry ae = null;
1095        Map JavaDoc lcache = null;
1096        if (GET_AVAILABLE_CACHE != null) {
1097            lcache = (Map JavaDoc) GET_AVAILABLE_CACHE.get();
1098            if (lcache != null) {
1099                ae = (AvailEntry) lcache.get(key);
1100            }
1101        }
1102
1103        if (ae == null) {
1104            ae = new AvailEntry(key);
1105            if (lcache == null) {
1106                lcache = new HashMap JavaDoc();
1107                lcache.put(key, ae);
1108                GET_AVAILABLE_CACHE = new SoftReference JavaDoc(lcache);
1109            } else {
1110                lcache.put(key, ae);
1111            }
1112        }
1113
1114        return ae;
1115    }
1116
1117    protected static final ICUResourceBundle findResourceWithFallback(String JavaDoc path,
1118            ICUResourceBundle actualBundle, ICUResourceBundle requested) {
1119        ICUResourceBundle sub = null;
1120        if (requested == null) {
1121            requested = actualBundle;
1122        }
1123        while (actualBundle != null) {
1124            StringTokenizer st = new StringTokenizer(path, "/");
1125            ICUResourceBundle current = actualBundle;
1126            while (st.hasMoreTokens()) {
1127                String JavaDoc subKey = st.nextToken();
1128                sub = current.handleGet(subKey, requested);
1129                if (sub == null) {
1130                    break;
1131                }
1132                current = sub;
1133            }
1134            if (sub != null) {
1135                //we found it
1136
break;
1137            }
1138            if (actualBundle.resPath.length() != 0) {
1139                path = actualBundle.resPath + "/" + path;
1140            }
1141            // if not try the parent bundle
1142
actualBundle = (ICUResourceBundle) actualBundle.getParent();
1143
1144        }
1145        if(sub != null){
1146            setLoadingStatus(sub, requested.getLocaleID());
1147        }
1148        return sub;
1149    }
1150    public boolean equals(Object JavaDoc other) {
1151        if (other instanceof ICUResourceBundle) {
1152            ICUResourceBundle o = (ICUResourceBundle) other;
1153            if (getBaseName().equals(o.getBaseName())
1154                    && getLocaleID().equals(o.getLocaleID())) {
1155                return true;
1156            }
1157        }
1158        return false;
1159    }
1160    // This method is for super class's instantiateBundle method
1161
public static UResourceBundle getBundleInstance(String JavaDoc baseName, String JavaDoc localeID,
1162                                                    ClassLoader JavaDoc root, boolean disableFallback){
1163        UResourceBundle b = instantiateBundle(baseName, localeID, root, disableFallback);
1164        if(b==null){
1165            throw new MissingResourceException JavaDoc("Could not find the bundle "+ baseName+"/"+ localeID+".res","","");
1166        }
1167        return b;
1168    }
1169    // recursively build bundle .. over-ride super class method.
1170
protected synchronized static UResourceBundle instantiateBundle(String JavaDoc baseName, String JavaDoc localeID,
1171                                                                    ClassLoader JavaDoc root, boolean disableFallback){
1172        ULocale defaultLocale = ULocale.getDefault();
1173        String JavaDoc localeName = localeID;
1174        if(localeName.indexOf('@')>0){
1175            localeName = ULocale.getBaseName(localeID);
1176        }
1177        String JavaDoc fullName = ICUResourceBundleReader.getFullName(baseName, localeName);
1178        ICUResourceBundle b = (ICUResourceBundle)loadFromCache(root, fullName, defaultLocale);
1179        
1180        // here we assume that java type resource bundle organization
1181
// is required then the base name contains '.' else
1182
// the resource organization is of ICU type
1183
// so clients can instantiate resources of the type
1184
// com.mycompany.data.MyLocaleElements_en.res and
1185
// com.mycompany.data.MyLocaleElements.res
1186
//
1187
final String JavaDoc rootLocale = (baseName.indexOf('.')==-1) ? "root" : "";
1188        final String JavaDoc defaultID = ULocale.getDefault().toString();
1189        
1190        if(localeName.equals("")){
1191            localeName = rootLocale;
1192        }
1193        if(DEBUG) System.out.println("Creating "+fullName+ " currently b is "+b);
1194        if (b == null) {
1195            b = ICUResourceBundleImpl.createBundle(baseName, localeName, root);
1196            
1197            if(DEBUG)System.out.println("The bundle created is: "+b+" and disableFallback="+disableFallback+" and bundle.getNoFallback="+(b!=null && b.getNoFallback()));
1198            if(disableFallback || (b!=null && b.getNoFallback())){
1199                addToCache(root, fullName, defaultLocale, b);
1200                // no fallback because the caller said so or because the bundle says so
1201
return b;
1202            }
1203
1204            // fallback to locale ID parent
1205
if(b == null){
1206                int i = localeName.lastIndexOf('_');
1207                if (i != -1) {
1208                    String JavaDoc temp = localeName.substring(0, i);
1209                    b = (ICUResourceBundle)instantiateBundle(baseName, temp, root, disableFallback);
1210                    if(b!=null && b.getULocale().equals(temp)){
1211                        b.setLoadingStatus(ICUResourceBundle.FROM_FALLBACK);
1212                    }
1213                }else{
1214                    if(defaultID.indexOf(localeName)==-1){
1215                        b = (ICUResourceBundle)instantiateBundle(baseName, defaultID, root, disableFallback);
1216                        if(b!=null){
1217                            b.setLoadingStatus(ICUResourceBundle.FROM_DEFAULT);
1218                        }
1219                    }else if(rootLocale.length()!=0){
1220                        b = ICUResourceBundleImpl.createBundle(baseName, rootLocale, root);
1221                        if(b!=null){
1222                            b.setLoadingStatus(ICUResourceBundle.FROM_ROOT);
1223                        }
1224                    }
1225                }
1226            }else{
1227                UResourceBundle parent = null;
1228                localeName = b.getLocaleID();
1229                int i = localeName.lastIndexOf('_');
1230                
1231                addToCache(root, fullName, defaultLocale, b);
1232                
1233                if (i != -1) {
1234                    parent = instantiateBundle(baseName, localeName.substring(0, i), root, disableFallback);
1235                }else if(!localeName.equals(rootLocale)){
1236                    parent = instantiateBundle(baseName, rootLocale, root, true);
1237                }
1238                
1239                if(!b.equals(parent)){
1240                    b.setParent(parent);
1241                }
1242            }
1243        }
1244        return b;
1245    }
1246}
1247
Popular Tags