12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others.
22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*******************************************************************************
52d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert* Copyright (C) 2003-2016, International Business Machines Corporation and
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* others. All Rights Reserved.
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*******************************************************************************
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*/
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.text;
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException;
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set;
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
162d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubertimport com.ibm.icu.impl.ICUData;
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICULocaleService;
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICULocaleService.LocaleKeyFactory;
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUResourceBundle;
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUService;
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUService.Factory;
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.coll.CollationLoader;
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.coll.CollationTailoring;
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.Collator.CollatorFactory;
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ICUCloneNotSupportedException;
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Output;
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale;
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertfinal class CollatorServiceShim extends Collator.ServiceShim {
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
312d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    @Override
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    Collator getInstance(ULocale locale) {
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // use service cache, it's faster than instantiation
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//          if (service.isDefault()) {
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//              return new RuleBasedCollator(locale);
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//          }
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ULocale[] actualLoc = new ULocale[1];
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            Collator coll = (Collator)service.get(locale, actualLoc);
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (coll == null) {
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ///CLOVER:OFF
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                //Can't really change coll after it's been initialized
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new MissingResourceException("Could not locate Collator data", "", "");
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ///CLOVER:ON
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return (Collator) coll.clone();
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        catch (CloneNotSupportedException e) {
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ///CLOVER:OFF
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new ICUCloneNotSupportedException(e);
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ///CLOVER:ON
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
552d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    @Override
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    Object registerInstance(Collator collator, ULocale locale) {
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Set the collator locales while registering so that getInstance()
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // need not guess whether the collator's locales are already set properly
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // (as they are by the data loader).
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        collator.setLocale(locale, locale);
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return service.registerObject(collator, locale);
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
642d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    @Override
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    Object registerFactory(CollatorFactory f) {
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        class CFactory extends LocaleKeyFactory {
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            CollatorFactory delegate;
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            CFactory(CollatorFactory fctry) {
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                super(fctry.visible());
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                this.delegate = fctry;
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
742d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert            @Override
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            public Object handleCreate(ULocale loc, int kind, ICUService srvc) {
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Object coll = delegate.createCollator(loc);
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return coll;
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
802d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert            @Override
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            public String getDisplayName(String id, ULocale displayLocale) {
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ULocale objectLocale = new ULocale(id);
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return delegate.getDisplayName(objectLocale, displayLocale);
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
862d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert            @Override
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            public Set<String> getSupportedIDs() {
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return delegate.getSupportedLocaleIDs();
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return service.registerFactory(new CFactory(f));
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
952d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    @Override
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    boolean unregister(Object registryKey) {
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return service.unregisterFactory((Factory)registryKey);
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1002d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    @Override
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    Locale[] getAvailableLocales() {
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // TODO rewrite this to just wrap getAvailableULocales later
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Locale[] result;
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (service.isDefault()) {
1052d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert            result = ICUResourceBundle.getAvailableLocales(ICUData.ICU_COLLATION_BASE_NAME,
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ICUResourceBundle.ICU_DATA_CLASS_LOADER);
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            result = service.getAvailableLocales();
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return result;
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1132d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    @Override
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ULocale[] getAvailableULocales() {
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ULocale[] result;
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (service.isDefault()) {
1172d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert            result = ICUResourceBundle.getAvailableULocales(ICUData.ICU_COLLATION_BASE_NAME,
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ICUResourceBundle.ICU_DATA_CLASS_LOADER);
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            result = service.getAvailableULocales();
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return result;
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1252d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    @Override
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    String getDisplayName(ULocale objectLocale, ULocale displayLocale) {
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String id = objectLocale.getName();
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return service.getDisplayName(id, displayLocale);
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static class CService extends ICULocaleService {
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CService() {
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            super("Collator");
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            class CollatorFactory extends ICUResourceBundleFactory {
1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                CollatorFactory() {
1372d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                    super(ICUData.ICU_COLLATION_BASE_NAME);
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
140f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                @Override
1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                protected Object handleCreate(ULocale uloc, int kind, ICUService srvc) {
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return makeInstance(uloc);
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.registerFactory(new CollatorFactory());
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            markDefault();
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
149f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
150f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /**
151f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         * makeInstance() returns an appropriate Collator for any locale.
152f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         * It falls back to root if there is no specific data.
153f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         *
154f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         * <p>Without this override, the service code would fall back to the default locale
155f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         * which is not desirable for an algorithm with a good Unicode default,
156f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         * like collation.
157f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         */
158f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        @Override
159f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        public String validateFallbackLocale() {
160f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            return "";
161f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
162f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ///CLOVER:OFF
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // The following method can not be reached by testing
1652d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        protected Object handleDefault(Key key, String[] actualIDReturn) {
1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (actualIDReturn != null) {
1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                actualIDReturn[0] = "root";
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            try {
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return makeInstance(ULocale.ROOT);
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            catch (MissingResourceException e) {
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return null;
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ///CLOVER:ON
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Ported from C++ Collator::makeInstance().
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final Collator makeInstance(ULocale desiredLocale) {
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Output<ULocale> validLocale = new Output<ULocale>(ULocale.ROOT);
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CollationTailoring t =
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            CollationLoader.loadTailoring(desiredLocale, validLocale);
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return new RuleBasedCollator(t, validLocale.value);
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static ICULocaleService service = new CService();
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
190