13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.util.cldr; 27 28 import java.security.AccessController; 29 import java.security.PrivilegedActionException; 30 import java.security.PrivilegedExceptionAction; 31 import java.text.spi.BreakIteratorProvider; 32 import java.text.spi.CollatorProvider; 33 import java.util.Collections; 34 import java.util.HashSet; 35 import java.util.Locale; 36 import java.util.ServiceLoader; 37 import java.util.Set; 38 import java.util.StringTokenizer; 39 import sun.util.locale.provider.JRELocaleProviderAdapter; 40 import sun.util.locale.provider.LocaleProviderAdapter; 41 import sun.util.locale.provider.LocaleDataMetaInfo; 42 43 /** 44 * LocaleProviderAdapter implementation for the CLDR locale data. 45 * 46 * @author Masayoshi Okutsu 47 * @author Naoto Sato 48 */ 49 public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { 50 51 private final LocaleDataMetaInfo metaInfo; 52 53 public CLDRLocaleProviderAdapter() { 54 try { 55 metaInfo = AccessController.doPrivileged(new PrivilegedExceptionAction<LocaleDataMetaInfo>() { 56 @Override 57 public LocaleDataMetaInfo run() { 58 for (LocaleDataMetaInfo ldmi : ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) { 59 if (ldmi.getType() == LocaleProviderAdapter.Type.CLDR) { 60 return ldmi; 61 } 62 } 63 return null; 64 } 65 }); 66 } catch (Exception e) { 67 // Catch any exception, and fail gracefully as if CLDR locales do not exist. 68 // It's ok ignore it if something wrong happens because there always is the 69 // JRE or FALLBACK LocaleProviderAdapter that will do the right thing. 70 throw new UnsupportedOperationException(e); 71 } 72 73 if (metaInfo == null) { 74 throw new UnsupportedOperationException("CLDR locale data could not be found."); 75 } 76 } 77 78 /** 79 * Returns the type of this LocaleProviderAdapter 80 * @return the type of this 81 */ 82 @Override 83 public LocaleProviderAdapter.Type getAdapterType() { 84 return LocaleProviderAdapter.Type.CLDR; 85 } 86 87 @Override 88 public BreakIteratorProvider getBreakIteratorProvider() { 89 return null; 90 } 91 92 @Override 93 public CollatorProvider getCollatorProvider() { 94 return null; 95 } 96 97 @Override 98 public Locale[] getAvailableLocales() { 99 Set<String> all = createLanguageTagSet("AvailableLocales"); 100 Locale[] locs = new Locale[all.size()]; 101 int index = 0; 102 for (String tag : all) { 103 locs[index++] = Locale.forLanguageTag(tag); 104 } 105 return locs; 106 } 107 108 @Override 109 protected Set<String> createLanguageTagSet(String category) { 110 String supportedLocaleString = metaInfo.availableLanguageTags(category); 111 if (supportedLocaleString == null) { 112 return Collections.emptySet(); 113 } 114 Set<String> tagset = new HashSet<>(); 115 StringTokenizer tokens = new StringTokenizer(supportedLocaleString); 116 while (tokens.hasMoreTokens()) { 117 tagset.add(tokens.nextToken()); 118 } 119 return tagset; 120 } 121 } | 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.util.cldr; 27 28 import java.security.AccessController; 29 import java.security.PrivilegedActionException; 30 import java.security.PrivilegedExceptionAction; 31 import java.text.spi.BreakIteratorProvider; 32 import java.text.spi.CollatorProvider; 33 import java.util.Arrays; 34 import java.util.Collections; 35 import java.util.HashSet; 36 import java.util.List; 37 import java.util.Locale; 38 import java.util.Map; 39 import java.util.Objects; 40 import java.util.ServiceLoader; 41 import java.util.Set; 42 import java.util.StringTokenizer; 43 import java.util.concurrent.ConcurrentHashMap; 44 import java.util.concurrent.ConcurrentMap; 45 import sun.util.locale.provider.JRELocaleProviderAdapter; 46 import sun.util.locale.provider.LocaleProviderAdapter; 47 import sun.util.locale.provider.LocaleDataMetaInfo; 48 49 /** 50 * LocaleProviderAdapter implementation for the CLDR locale data. 51 * 52 * @author Masayoshi Okutsu 53 * @author Naoto Sato 54 */ 55 public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { 56 57 private static final CLDRBaseLocaleDataMetaInfo baseMetaInfo = new CLDRBaseLocaleDataMetaInfo(); 58 // Assumption: CLDR has only one non-Base module. 59 private final LocaleDataMetaInfo nonBaseMetaInfo; 60 61 // parent locales map 62 private static ConcurrentMap<Locale, Locale> parentLocalesMap = null; 63 64 public CLDRLocaleProviderAdapter() { 65 try { 66 nonBaseMetaInfo = AccessController.doPrivileged(new PrivilegedExceptionAction<LocaleDataMetaInfo>() { 67 @Override 68 public LocaleDataMetaInfo run() { 69 for (LocaleDataMetaInfo ldmi : ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) { 70 if (ldmi.getType() == LocaleProviderAdapter.Type.CLDR) { 71 return ldmi; 72 } 73 } 74 return null; 75 } 76 }); 77 } catch (Exception e) { 78 // Catch any exception, and fail gracefully as if CLDR locales do not exist. 79 // It's ok ignore it if something wrong happens because there always is the 80 // JRE or FALLBACK LocaleProviderAdapter that will do the right thing. 81 throw new UnsupportedOperationException(e); 82 } 83 84 if (nonBaseMetaInfo == null) { 85 throw new UnsupportedOperationException("CLDR locale data could not be found."); 86 } 87 } 88 89 /** 90 * Returns the type of this LocaleProviderAdapter 91 * @return the type of this 92 */ 93 @Override 94 public LocaleProviderAdapter.Type getAdapterType() { 95 return LocaleProviderAdapter.Type.CLDR; 96 } 97 98 @Override 99 public BreakIteratorProvider getBreakIteratorProvider() { 100 return null; 101 } 102 103 @Override 104 public CollatorProvider getCollatorProvider() { 105 return null; 106 } 107 108 @Override 109 public Locale[] getAvailableLocales() { 110 Set<String> all = createLanguageTagSet("AvailableLocales"); 111 Locale[] locs = new Locale[all.size()]; 112 int index = 0; 113 for (String tag : all) { 114 locs[index++] = Locale.forLanguageTag(tag); 115 } 116 return locs; 117 } 118 119 @Override 120 protected Set<String> createLanguageTagSet(String category) { 121 // Directly call Base tags, as we know it's in the base module. 122 String supportedLocaleString = baseMetaInfo.availableLanguageTags(category); 123 String nonBaseTags = nonBaseMetaInfo.availableLanguageTags(category); 124 if (nonBaseTags != null) { 125 if (supportedLocaleString != null) { 126 supportedLocaleString += " " + nonBaseTags; 127 } else { 128 supportedLocaleString = nonBaseTags; 129 } 130 } 131 if (supportedLocaleString == null) { 132 return Collections.emptySet(); 133 } 134 Set<String> tagset = new HashSet<>(); 135 StringTokenizer tokens = new StringTokenizer(supportedLocaleString); 136 while (tokens.hasMoreTokens()) { 137 tagset.add(tokens.nextToken()); 138 } 139 return tagset; 140 } 141 142 // Implementation of ResourceBundleBasedAdapter 143 @Override 144 public List<Locale> getCandidateLocales(String baseName, Locale locale) { 145 List<Locale> candidates = super.getCandidateLocales(baseName, locale); 146 return applyParentLocales(baseName, candidates); 147 } 148 149 private List<Locale> applyParentLocales(String baseName, List<Locale> candidates) { 150 if (Objects.isNull(parentLocalesMap)) { 151 parentLocalesMap = new ConcurrentHashMap<>(); 152 Map<String, String> parentLocales = baseMetaInfo.parentLocales(); 153 parentLocales.keySet().forEach(parent -> { 154 Arrays.asList(parentLocales.get(parent).split(" ")).stream().forEach(child -> { 155 parentLocalesMap.put(Locale.forLanguageTag(child), 156 "root".equals(parent) ? Locale.ROOT : Locale.forLanguageTag(parent)); 157 }); 158 }); 159 } 160 161 // check irregular parents 162 for (int i = 0; i < candidates.size(); i++) { 163 Locale l = candidates.get(i); 164 Locale p = parentLocalesMap.get(l); 165 if (!l.equals(Locale.ROOT) && 166 Objects.nonNull(p) && 167 !candidates.get(i+1).equals(p)) { 168 List<Locale> applied = candidates.subList(0, i+1); 169 applied.addAll(applyParentLocales(baseName, super.getCandidateLocales(baseName, p))); 170 return applied; 171 } 172 } 173 174 return candidates; 175 } 176 177 @Override 178 public boolean isSupportedProviderLocale(Locale locale, Set<String> langtags) { 179 return Locale.ROOT.equals(locale) || 180 langtags.contains(locale.stripExtensions().toLanguageTag()); 181 } 182 } |