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