]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/classes/core/src/com/ibm/icu/impl/ICULocaleService.java
Clean up imports.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / core / src / com / ibm / icu / impl / ICULocaleService.java
1 /**
2  *******************************************************************************
3  * Copyright (C) 2001-2011, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 package com.ibm.icu.impl;
8
9 import java.util.Collections;
10 import java.util.Locale;
11 import java.util.Map;
12 import java.util.Set;
13
14 import com.ibm.icu.util.ULocale;
15
16 public class ICULocaleService extends ICUService {
17     private ULocale fallbackLocale;
18     private String fallbackLocaleName;
19
20     /**
21      * Construct an ICULocaleService.
22      */
23     public ICULocaleService() {
24     }
25
26     /**
27      * Construct an ICULocaleService with a name (useful for debugging).
28      */
29     public ICULocaleService(String name) {
30         super(name);
31     }
32
33     /**
34      * Convenience override for callers using locales.  This calls
35      * get(ULocale, int, ULocale[]) with KIND_ANY for kind and null for
36      * actualReturn.
37      */
38     public Object get(ULocale locale) {
39         return get(locale, LocaleKey.KIND_ANY, null);
40     }
41
42     /**
43      * Convenience override for callers using locales.  This calls
44      * get(ULocale, int, ULocale[]) with a null actualReturn.
45      */
46     public Object get(ULocale locale, int kind) {
47         return get(locale, kind, null);
48     }
49
50     /**
51      * Convenience override for callers using locales.  This calls
52      * get(ULocale, int, ULocale[]) with KIND_ANY for kind.
53      */
54     public Object get(ULocale locale, ULocale[] actualReturn) {
55         return get(locale, LocaleKey.KIND_ANY, actualReturn);
56     }
57
58     /**
59      * Convenience override for callers using locales.  This uses
60      * createKey(ULocale.toString(), kind) to create a key, calls getKey, and then
61      * if actualReturn is not null, returns the actualResult from
62      * getKey (stripping any prefix) into a ULocale.  
63      */
64     public Object get(ULocale locale, int kind, ULocale[] actualReturn) {
65         Key key = createKey(locale, kind);
66         if (actualReturn == null) {
67             return getKey(key);
68         }
69
70         String[] temp = new String[1];
71         Object result = getKey(key, temp);
72         if (result != null) {
73             int n = temp[0].indexOf("/");
74             if (n >= 0) {
75                 temp[0] = temp[0].substring(n+1);
76             }
77             actualReturn[0] = new ULocale(temp[0]);
78         }
79         return result;
80     }
81
82     /**
83      * Convenience override for callers using locales.  This calls
84      * registerObject(Object, ULocale, int kind, boolean visible)
85      * passing KIND_ANY for the kind, and true for the visibility.
86      */
87     public Factory registerObject(Object obj, ULocale locale) {
88         return registerObject(obj, locale, LocaleKey.KIND_ANY, true);
89     }
90
91     /**
92      * Convenience override for callers using locales.  This calls
93      * registerObject(Object, ULocale, int kind, boolean visible)
94      * passing KIND_ANY for the kind.
95      */
96     public Factory registerObject(Object obj, ULocale locale, boolean visible) {
97         return registerObject(obj, locale, LocaleKey.KIND_ANY, visible);
98     }
99
100     /**
101      * Convenience function for callers using locales.  This calls
102      * registerObject(Object, ULocale, int kind, boolean visible)
103      * passing true for the visibility.
104      */
105     public Factory registerObject(Object obj, ULocale locale, int kind) {
106         return registerObject(obj, locale, kind, true);
107     }
108
109     /**
110      * Convenience function for callers using locales.  This  instantiates
111      * a SimpleLocaleKeyFactory, and registers the factory.
112      */
113     public Factory registerObject(Object obj, ULocale locale, int kind, boolean visible) {
114         Factory factory = new SimpleLocaleKeyFactory(obj, locale, kind, visible);
115         return registerFactory(factory);
116     }
117
118     /**
119      * Convenience method for callers using locales.  This returns the standard
120      * Locale list, built from the Set of visible ids.
121      */
122     public Locale[] getAvailableLocales() {
123         // TODO make this wrap getAvailableULocales later
124         Set<String> visIDs = getVisibleIDs();
125         Locale[] locales = new Locale[visIDs.size()];
126         int n = 0;
127         for (String id : visIDs) {
128             Locale loc = LocaleUtility.getLocaleFromName(id);
129             locales[n++] = loc;
130         }
131         return locales;
132     }
133
134     /**
135      * Convenience method for callers using locales.  This returns the standard
136      * ULocale list, built from the Set of visible ids.
137      */
138     public ULocale[] getAvailableULocales() {
139         Set<String> visIDs = getVisibleIDs();
140         ULocale[] locales = new ULocale[visIDs.size()];
141         int n = 0;
142         for (String id : visIDs) {
143             locales[n++] = new ULocale(id);
144         }
145         return locales;
146     }
147         
148     /**
149      * A subclass of Key that implements a locale fallback mechanism.
150      * The first locale to search for is the locale provided by the
151      * client, and the fallback locale to search for is the current
152      * default locale.  If a prefix is present, the currentDescriptor
153      * includes it before the locale proper, separated by "/".  This
154      * is the default key instantiated by ICULocaleService.</p>
155      *
156      * <p>Canonicalization adjusts the locale string so that the
157      * section before the first understore is in lower case, and the rest
158      * is in upper case, with no trailing underscores.</p> 
159      */
160     public static class LocaleKey extends ICUService.Key {
161         private int kind;
162         private int varstart;
163         private String primaryID;
164         private String fallbackID;
165         private String currentID;
166
167         public static final int KIND_ANY = -1;
168
169         /**
170          * Create a LocaleKey with canonical primary and fallback IDs.
171          */
172         public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID) {
173             return createWithCanonicalFallback(primaryID, canonicalFallbackID, KIND_ANY);
174         }
175             
176         /**
177          * Create a LocaleKey with canonical primary and fallback IDs.
178          */
179         public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID, int kind) {
180             if (primaryID == null) {
181                 return null;
182             }
183             String canonicalPrimaryID = ULocale.getName(primaryID);
184             return new LocaleKey(primaryID, canonicalPrimaryID, canonicalFallbackID, kind);
185         }
186             
187         /**
188          * Create a LocaleKey with canonical primary and fallback IDs.
189          */
190         public static LocaleKey createWithCanonical(ULocale locale, String canonicalFallbackID, int kind) {
191             if (locale == null) {
192                 return null;
193             }
194             String canonicalPrimaryID = locale.getName();
195             return new LocaleKey(canonicalPrimaryID, canonicalPrimaryID, canonicalFallbackID, kind);
196         }
197             
198         /**
199          * PrimaryID is the user's requested locale string,
200          * canonicalPrimaryID is this string in canonical form,
201          * fallbackID is the current default locale's string in
202          * canonical form.
203          */
204         protected LocaleKey(String primaryID, String canonicalPrimaryID, String canonicalFallbackID, int kind) {
205             super(primaryID);
206             this.kind = kind;
207
208             if (canonicalPrimaryID == null || canonicalPrimaryID.equalsIgnoreCase("root")) {
209                 this.primaryID = "";
210                 this.fallbackID = null;
211             } else {
212                 int idx = canonicalPrimaryID.indexOf('@');
213                 if (idx == 4 && canonicalPrimaryID.regionMatches(true, 0, "root", 0, 4)) {
214                     this.primaryID = canonicalPrimaryID.substring(4);
215                     this.varstart = 0;
216                     this.fallbackID = null;
217                 } else {
218                     this.primaryID = canonicalPrimaryID;
219                     this.varstart = idx;
220
221                     if (canonicalFallbackID == null || this.primaryID.equals(canonicalFallbackID)) {
222                         this.fallbackID = "";
223                     } else {
224                         this.fallbackID = canonicalFallbackID;
225                     }
226                 }
227             }
228
229             this.currentID = varstart == -1 ? this.primaryID : this.primaryID.substring(0, varstart);
230         }
231
232         /**
233          * Return the prefix associated with the kind, or null if the kind is KIND_ANY.
234          */
235         public String prefix() {
236             return kind == KIND_ANY ? null : Integer.toString(kind());
237         }
238
239         /**
240          * Return the kind code associated with this key.
241          */
242         public int kind() {
243             return kind;
244         }
245
246         /**
247          * Return the (canonical) original ID.
248          */
249         public String canonicalID() {
250             return primaryID;
251         }
252
253         /**
254          * Return the (canonical) current ID, or null if no current id.
255          */
256         public String currentID() {
257             return currentID;
258         }
259
260         /**
261          * Return the (canonical) current descriptor, or null if no current id.
262          * Includes the keywords, whereas the ID does not include keywords.
263          */
264         public String currentDescriptor() {
265             String result = currentID();
266             if (result != null) {
267                 StringBuilder buf = new StringBuilder(); // default capacity 16 is usually good enough
268                 if (kind != KIND_ANY) {
269                     buf.append(prefix());
270                 }
271                 buf.append('/');
272                 buf.append(result);
273                 if (varstart != -1) {
274                     buf.append(primaryID.substring(varstart, primaryID.length()));
275                 }
276                 result = buf.toString();
277             }
278             return result;
279         }
280
281         /**
282          * Convenience method to return the locale corresponding to the (canonical) original ID.
283          */
284         public ULocale canonicalLocale() {
285             return new ULocale(primaryID);
286         }
287
288         /**
289          * Convenience method to return the ulocale corresponding to the (canonical) currentID.
290          */
291         public ULocale currentLocale() {
292             if (varstart == -1) {
293                 return new ULocale(currentID);
294             } else {
295                 return new ULocale(currentID + primaryID.substring(varstart));
296             }
297         }
298
299         /**
300          * If the key has a fallback, modify the key and return true,
301          * otherwise return false.</p>
302          *
303          * <p>First falls back through the primary ID, then through
304          * the fallbackID.  The final fallback is "" (root)
305          * unless the primary id was "" (root), in which case
306          * there is no fallback.  
307          */
308         public boolean fallback() {
309             int x = currentID.lastIndexOf('_');
310             if (x != -1) {
311                 while (--x >= 0 && currentID.charAt(x) == '_') { // handle zh__PINYIN
312                 }
313                 currentID = currentID.substring(0, x+1);
314                 return true;
315             }
316             if (fallbackID != null) {
317                 currentID = fallbackID;
318                 if (fallbackID.length() == 0) {
319                     fallbackID = null;
320                 } else {
321                     fallbackID = "";
322                 }
323                 return true;
324             }
325             currentID = null;
326             return false;
327         }
328
329         /**
330          * If a key created from id would eventually fallback to match the 
331          * canonical ID of this key, return true.
332          */
333         public boolean isFallbackOf(String id) {
334             return LocaleUtility.isFallbackOf(canonicalID(), id);
335         }
336     }
337
338     /**
339      * A subclass of Factory that uses LocaleKeys.  If 'visible' the
340      * factory reports its IDs.
341      */
342     public static abstract class LocaleKeyFactory implements Factory {
343         protected final String name;
344         protected final boolean visible;
345
346         public static final boolean VISIBLE = true;
347         public static final boolean INVISIBLE = false;
348
349         /**
350          * Constructor used by subclasses.
351          */
352         protected LocaleKeyFactory(boolean visible) {
353             this.visible = visible;
354             this.name = null;
355         }
356
357         /**
358          * Constructor used by subclasses.
359          */
360         protected LocaleKeyFactory(boolean visible, String name) {
361             this.visible = visible;
362             this.name = name;
363         }
364
365         /**
366          * Implement superclass abstract method.  This checks the currentID of
367          * the key against the supported IDs, and passes the canonicalLocale and
368          * kind off to handleCreate (which subclasses must implement).
369          */
370         public Object create(Key key, ICUService service) {
371             if (handlesKey(key)) {
372                 LocaleKey lkey = (LocaleKey)key;
373                 int kind = lkey.kind();
374                 
375                 ULocale uloc = lkey.currentLocale();
376                 return handleCreate(uloc, kind, service);
377             } else {
378                 // System.out.println("factory: " + this + " did not support id: " + key.currentID());
379                 // System.out.println("supported ids: " + getSupportedIDs());
380             }
381             return null;
382         }
383
384         protected boolean handlesKey(Key key) {
385             if (key != null) {
386                 String id = key.currentID();
387                 Set<String> supported = getSupportedIDs();
388                 return supported.contains(id);
389             }
390             return false;
391         }
392
393         /**
394          * Override of superclass method.
395          */
396         public void updateVisibleIDs(Map<String, Factory> result) {
397             Set<String> cache = getSupportedIDs();
398             for (String id : cache) {
399                 if (visible) {
400                     result.put(id, this);
401                 } else {
402                     result.remove(id);
403                 }
404             }
405        }
406
407         /**
408          * Return a localized name for the locale represented by id.
409          */
410         public String getDisplayName(String id, ULocale locale) {
411             // assume if the user called this on us, we must have handled some fallback of this id
412             //          if (isSupportedID(id)) {
413             if (locale == null) {
414                 return id;
415             }
416             ULocale loc = new ULocale(id);
417             return loc.getDisplayName(locale);
418             //              }
419             //          return null;
420         }
421
422         ///CLOVER:OFF
423         /**
424          * Utility method used by create(Key, ICUService).  Subclasses can
425          * implement this instead of create.
426          */
427         protected Object handleCreate(ULocale loc, int kind, ICUService service) {
428             return null;
429         }
430         ///CLOVER:ON
431
432         /**
433          * Return true if this id is one the factory supports (visible or 
434          * otherwise).
435          */
436         protected boolean isSupportedID(String id) {
437             return getSupportedIDs().contains(id);
438         }
439         
440         /**
441          * Return the set of ids that this factory supports (visible or 
442          * otherwise).  This can be called often and might need to be
443          * cached if it is expensive to create.
444          */
445         protected Set<String> getSupportedIDs() {
446             return Collections.emptySet();
447         }
448
449         /**
450          * For debugging.
451          */
452         public String toString() {
453             StringBuilder buf = new StringBuilder(super.toString());
454             if (name != null) {
455                 buf.append(", name: ");
456                 buf.append(name);
457             }
458             buf.append(", visible: ");
459             buf.append(visible);
460             return buf.toString();
461         }
462     }
463
464     /**
465      * A LocaleKeyFactory that just returns a single object for a kind/locale.
466      */
467     public static class SimpleLocaleKeyFactory extends LocaleKeyFactory {
468         private final Object obj;
469         private final String id;
470         private final int kind;
471
472         // TODO: remove when we no longer need this
473         public SimpleLocaleKeyFactory(Object obj, ULocale locale, int kind, boolean visible) {
474             this(obj, locale, kind, visible, null);
475         }
476
477         public SimpleLocaleKeyFactory(Object obj, ULocale locale, int kind, boolean visible, String name) {
478             super(visible, name);
479             
480             this.obj = obj;
481             this.id = locale.getBaseName();
482             this.kind = kind;
483         }
484
485         /**
486          * Returns the service object if kind/locale match.  Service is not used.
487          */
488         public Object create(Key key, ICUService service) {
489             if (!(key instanceof LocaleKey)) {
490                 return null;
491             }
492             
493             LocaleKey lkey = (LocaleKey)key;
494             if (kind != LocaleKey.KIND_ANY && kind != lkey.kind()) {
495                 return null;
496             }
497             if (!id.equals(lkey.currentID())) {
498                 return null;
499             }
500             
501             return obj;
502         }
503
504         protected boolean isSupportedID(String idToCheck) {
505             return this.id.equals(idToCheck);
506         }
507
508         public void updateVisibleIDs(Map<String, Factory> result) {
509             if (visible) {
510                 result.put(id, this);
511             } else {
512                 result.remove(id);
513             }
514         }
515
516         public String toString() {
517             StringBuilder buf = new StringBuilder(super.toString());
518             buf.append(", id: ");
519             buf.append(id);
520             buf.append(", kind: ");
521             buf.append(kind);
522             return buf.toString();
523         }
524     }
525
526     /**
527      * A LocaleKeyFactory that creates a service based on the ICU locale data.
528      * This is a base class for most ICU factories.  Subclasses instantiate it
529      * with a constructor that takes a bundle name, which determines the supported
530      * IDs.  Subclasses then override handleCreate to create the actual service
531      * object.  The default implementation returns a resource bundle.
532      */
533     public static class ICUResourceBundleFactory extends LocaleKeyFactory {
534         protected final String bundleName;
535
536         /**
537          * Convenience constructor that uses the main ICU bundle name.
538          */
539         public ICUResourceBundleFactory() {
540             this(ICUResourceBundle.ICU_BASE_NAME);
541         }
542
543         /**
544          * A service factory based on ICU resource data in resources
545          * with the given name.
546          */
547         public ICUResourceBundleFactory(String bundleName) {
548             super(true);
549
550             this.bundleName = bundleName;
551         }
552
553         /**
554          * Return the supported IDs.  This is the set of all locale names for the bundleName.
555          */
556         protected Set<String> getSupportedIDs() {
557             return ICUResourceBundle.getFullLocaleNameSet(bundleName, loader()); 
558         }
559
560         /**
561          * Override of superclass method.
562          */
563         public void updateVisibleIDs(Map<String, Factory> result) {
564           Set<String> visibleIDs = ICUResourceBundle.getAvailableLocaleNameSet(bundleName, loader()); // only visible ids
565             for (String id : visibleIDs) {
566                 result.put(id, this);
567             }
568         }
569
570         /**
571          * Create the service.  The default implementation returns the resource bundle
572          * for the locale, ignoring kind, and service.
573          */
574         protected Object handleCreate(ULocale loc, int kind, ICUService service) {
575             return ICUResourceBundle.getBundleInstance(bundleName, loc, loader());
576         }
577
578         protected ClassLoader loader() {
579             ClassLoader cl = getClass().getClassLoader();
580             if (cl == null) {
581                 cl = Utility.getFallbackClassLoader();
582             }
583             return cl;
584         }
585
586         public String toString() {
587             return super.toString() + ", bundle: " + bundleName;
588         }
589     }
590
591     /**
592      * Return the name of the current fallback locale.  If it has changed since this was
593      * last accessed, the service cache is cleared.
594      */
595     public String validateFallbackLocale() {
596         ULocale loc = ULocale.getDefault();
597         if (loc != fallbackLocale) {
598             synchronized (this) {
599                 if (loc != fallbackLocale) {
600                     fallbackLocale = loc;
601                     fallbackLocaleName = loc.getBaseName();
602                     clearServiceCache();
603                 }
604             }
605         }
606         return fallbackLocaleName;
607     }
608
609     public Key createKey(String id) {
610         return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale());
611     }
612
613     public Key createKey(String id, int kind) {
614         return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale(), kind);
615     }
616
617     public Key createKey(ULocale l, int kind) {
618         return LocaleKey.createWithCanonical(l, validateFallbackLocale(), kind);
619     }
620 }