1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html#License
3 /**
4 *******************************************************************************
5 * Copyright (C) 2003-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9 
10 package com.ibm.icu.text;
11 
12 import java.util.Locale;
13 import java.util.MissingResourceException;
14 import java.util.Set;
15 
16 import com.ibm.icu.impl.ICUData;
17 import com.ibm.icu.impl.ICULocaleService;
18 import com.ibm.icu.impl.ICULocaleService.LocaleKeyFactory;
19 import com.ibm.icu.impl.ICUResourceBundle;
20 import com.ibm.icu.impl.ICUService;
21 import com.ibm.icu.impl.ICUService.Factory;
22 import com.ibm.icu.impl.coll.CollationLoader;
23 import com.ibm.icu.impl.coll.CollationTailoring;
24 import com.ibm.icu.text.Collator.CollatorFactory;
25 import com.ibm.icu.util.ICUCloneNotSupportedException;
26 import com.ibm.icu.util.Output;
27 import com.ibm.icu.util.ULocale;
28 
29 final class CollatorServiceShim extends Collator.ServiceShim {
30 
31     @Override
getInstance(ULocale locale)32     Collator getInstance(ULocale locale) {
33     // use service cache, it's faster than instantiation
34 //          if (service.isDefault()) {
35 //              return new RuleBasedCollator(locale);
36 //          }
37         try {
38             ULocale[] actualLoc = new ULocale[1];
39             Collator coll = (Collator)service.get(locale, actualLoc);
40             if (coll == null) {
41                 ///CLOVER:OFF
42                 //Can't really change coll after it's been initialized
43                 throw new MissingResourceException("Could not locate Collator data", "", "");
44                 ///CLOVER:ON
45             }
46             return (Collator) coll.clone();
47         }
48         catch (CloneNotSupportedException e) {
49         ///CLOVER:OFF
50             throw new ICUCloneNotSupportedException(e);
51         ///CLOVER:ON
52         }
53     }
54 
55     @Override
registerInstance(Collator collator, ULocale locale)56     Object registerInstance(Collator collator, ULocale locale) {
57         // Set the collator locales while registering so that getInstance()
58         // need not guess whether the collator's locales are already set properly
59         // (as they are by the data loader).
60         collator.setLocale(locale, locale);
61         return service.registerObject(collator, locale);
62     }
63 
64     @Override
registerFactory(CollatorFactory f)65     Object registerFactory(CollatorFactory f) {
66         class CFactory extends LocaleKeyFactory {
67             CollatorFactory delegate;
68 
69             CFactory(CollatorFactory fctry) {
70                 super(fctry.visible());
71                 this.delegate = fctry;
72             }
73 
74             @Override
75             public Object handleCreate(ULocale loc, int kind, ICUService srvc) {
76                 Object coll = delegate.createCollator(loc);
77                 return coll;
78             }
79 
80             @Override
81             public String getDisplayName(String id, ULocale displayLocale) {
82                 ULocale objectLocale = new ULocale(id);
83                 return delegate.getDisplayName(objectLocale, displayLocale);
84             }
85 
86             @Override
87             public Set<String> getSupportedIDs() {
88                 return delegate.getSupportedLocaleIDs();
89             }
90         }
91 
92         return service.registerFactory(new CFactory(f));
93     }
94 
95     @Override
unregister(Object registryKey)96     boolean unregister(Object registryKey) {
97         return service.unregisterFactory((Factory)registryKey);
98     }
99 
100     @Override
getAvailableLocales()101     Locale[] getAvailableLocales() {
102         // TODO rewrite this to just wrap getAvailableULocales later
103         Locale[] result;
104         if (service.isDefault()) {
105             result = ICUResourceBundle.getAvailableLocales(ICUData.ICU_COLLATION_BASE_NAME,
106                     ICUResourceBundle.ICU_DATA_CLASS_LOADER);
107         } else {
108             result = service.getAvailableLocales();
109         }
110         return result;
111     }
112 
113     @Override
getAvailableULocales()114     ULocale[] getAvailableULocales() {
115         ULocale[] result;
116         if (service.isDefault()) {
117             result = ICUResourceBundle.getAvailableULocales(ICUData.ICU_COLLATION_BASE_NAME,
118                     ICUResourceBundle.ICU_DATA_CLASS_LOADER);
119         } else {
120             result = service.getAvailableULocales();
121         }
122         return result;
123     }
124 
125     @Override
getDisplayName(ULocale objectLocale, ULocale displayLocale)126     String getDisplayName(ULocale objectLocale, ULocale displayLocale) {
127         String id = objectLocale.getName();
128         return service.getDisplayName(id, displayLocale);
129     }
130 
131     private static class CService extends ICULocaleService {
CService()132         CService() {
133             super("Collator");
134 
135             class CollatorFactory extends ICUResourceBundleFactory {
136                 CollatorFactory() {
137                     super(ICUData.ICU_COLLATION_BASE_NAME);
138                 }
139 
140                 @Override
141                 protected Object handleCreate(ULocale uloc, int kind, ICUService srvc) {
142                     return makeInstance(uloc);
143                 }
144             }
145 
146             this.registerFactory(new CollatorFactory());
147             markDefault();
148         }
149 
150         /**
151          * makeInstance() returns an appropriate Collator for any locale.
152          * It falls back to root if there is no specific data.
153          *
154          * <p>Without this override, the service code would fall back to the default locale
155          * which is not desirable for an algorithm with a good Unicode default,
156          * like collation.
157          */
158         @Override
validateFallbackLocale()159         public String validateFallbackLocale() {
160             return "";
161         }
162 
163         ///CLOVER:OFF
164         // The following method can not be reached by testing
165         @Override
handleDefault(Key key, String[] actualIDReturn)166         protected Object handleDefault(Key key, String[] actualIDReturn) {
167             if (actualIDReturn != null) {
168                 actualIDReturn[0] = "root";
169             }
170             try {
171                 return makeInstance(ULocale.ROOT);
172             }
173             catch (MissingResourceException e) {
174                 return null;
175             }
176         }
177         ///CLOVER:ON
178     }
179 
180     // Ported from C++ Collator::makeInstance().
makeInstance(ULocale desiredLocale)181     private static final Collator makeInstance(ULocale desiredLocale) {
182         Output<ULocale> validLocale = new Output<ULocale>(ULocale.ROOT);
183         CollationTailoring t =
184             CollationLoader.loadTailoring(desiredLocale, validLocale);
185         return new RuleBasedCollator(t, validLocale.value);
186     }
187 
188     private static ICULocaleService service = new CService();
189 }
190