1/* GENERATED SOURCE. DO NOT MODIFY. */ 2// © 2016 and later: Unicode, Inc. and others. 3// License & terms of use: http://www.unicode.org/copyright.html#License 4/* 5 ******************************************************************************* 6 * Copyright (C) 2014-2016, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10package android.icu.impl.locale; 11 12import java.util.Collections; 13import java.util.EnumSet; 14import java.util.HashMap; 15import java.util.HashSet; 16import java.util.LinkedHashMap; 17import java.util.LinkedHashSet; 18import java.util.Map; 19import java.util.MissingResourceException; 20import java.util.Set; 21import java.util.regex.Pattern; 22 23import android.icu.impl.ICUData; 24import android.icu.impl.ICUResourceBundle; 25import android.icu.util.Output; 26import android.icu.util.UResourceBundle; 27import android.icu.util.UResourceBundleIterator; 28 29/** 30 * @hide Only a subset of ICU is exposed in Android 31 */ 32public class KeyTypeData { 33 34 public enum ValueType { 35 single, multiple, incremental, any 36 } 37 38 private static abstract class SpecialTypeHandler { 39 abstract boolean isWellFormed(String value); // doesn't test validity, just whether it is well formed. 40 String canonicalize(String value) { 41 return AsciiUtil.toLowerString(value); 42 } 43 } 44 45 private static class CodepointsTypeHandler extends SpecialTypeHandler { 46 private static final Pattern pat = Pattern.compile("[0-9a-fA-F]{4,6}(-[0-9a-fA-F]{4,6})*"); 47 @Override 48 boolean isWellFormed(String value) { 49 return pat.matcher(value).matches(); 50 } 51 } 52 53 private static class ReorderCodeTypeHandler extends SpecialTypeHandler { 54 private static final Pattern pat = Pattern.compile("[a-zA-Z]{3,8}(-[a-zA-Z]{3,8})*"); 55 @Override 56 boolean isWellFormed(String value) { 57 return pat.matcher(value).matches(); 58 } 59 } 60 61 private static class RgKeyValueTypeHandler extends SpecialTypeHandler { 62 private static final Pattern pat = Pattern.compile("([a-zA-Z]{2}|[0-9]{3})[zZ]{4}"); 63 @Override 64 boolean isWellFormed(String value) { 65 return pat.matcher(value).matches(); 66 } 67 } 68 69 private static class SubdivisionKeyValueTypeHandler extends SpecialTypeHandler { 70 private static final Pattern pat = Pattern.compile("([a-zA-Z]{2}|[0-9]{3})"); 71 @Override 72 boolean isWellFormed(String value) { 73 return pat.matcher(value).matches(); 74 } 75 } 76 77 private static class PrivateUseKeyValueTypeHandler extends SpecialTypeHandler { 78 private static final Pattern pat = Pattern.compile("[a-zA-Z0-9]{3,8}(-[a-zA-Z0-9]{3,8})*"); 79 @Override 80 boolean isWellFormed(String value) { 81 return pat.matcher(value).matches(); 82 } 83 } 84 85 private enum SpecialType { 86 CODEPOINTS(new CodepointsTypeHandler()), 87 REORDER_CODE(new ReorderCodeTypeHandler()), 88 RG_KEY_VALUE(new RgKeyValueTypeHandler()), 89 SUBDIVISION_CODE(new SubdivisionKeyValueTypeHandler()), 90 PRIVATE_USE(new PrivateUseKeyValueTypeHandler()), 91 ; 92 SpecialTypeHandler handler; 93 SpecialType(SpecialTypeHandler handler) { 94 this.handler = handler; 95 } 96 }; 97 98 private static class KeyData { 99 String legacyId; 100 String bcpId; 101 Map<String, Type> typeMap; 102 EnumSet<SpecialType> specialTypes; 103 104 KeyData(String legacyId, String bcpId, Map<String, Type> typeMap, 105 EnumSet<SpecialType> specialTypes) { 106 this.legacyId = legacyId; 107 this.bcpId = bcpId; 108 this.typeMap = typeMap; 109 this.specialTypes = specialTypes; 110 } 111 } 112 113 private static class Type { 114 String legacyId; 115 String bcpId; 116 117 Type(String legacyId, String bcpId) { 118 this.legacyId = legacyId; 119 this.bcpId = bcpId; 120 } 121 } 122 123 public static String toBcpKey(String key) { 124 key = AsciiUtil.toLowerString(key); 125 KeyData keyData = KEYMAP.get(key); 126 if (keyData != null) { 127 return keyData.bcpId; 128 } 129 return null; 130 } 131 132 public static String toLegacyKey(String key) { 133 key = AsciiUtil.toLowerString(key); 134 KeyData keyData = KEYMAP.get(key); 135 if (keyData != null) { 136 return keyData.legacyId; 137 } 138 return null; 139 } 140 141 public static String toBcpType(String key, String type, 142 Output<Boolean> isKnownKey, Output<Boolean> isSpecialType) { 143 144 if (isKnownKey != null) { 145 isKnownKey.value = false; 146 } 147 if (isSpecialType != null) { 148 isSpecialType.value = false; 149 } 150 151 key = AsciiUtil.toLowerString(key); 152 type = AsciiUtil.toLowerString(type); 153 154 KeyData keyData = KEYMAP.get(key); 155 if (keyData != null) { 156 if (isKnownKey != null) { 157 isKnownKey.value = Boolean.TRUE; 158 } 159 Type t = keyData.typeMap.get(type); 160 if (t != null) { 161 return t.bcpId; 162 } 163 if (keyData.specialTypes != null) { 164 for (SpecialType st : keyData.specialTypes) { 165 if (st.handler.isWellFormed(type)) { 166 if (isSpecialType != null) { 167 isSpecialType.value = true; 168 } 169 return st.handler.canonicalize(type); 170 } 171 } 172 } 173 } 174 return null; 175 } 176 177 178 public static String toLegacyType(String key, String type, 179 Output<Boolean> isKnownKey, Output<Boolean> isSpecialType) { 180 181 if (isKnownKey != null) { 182 isKnownKey.value = false; 183 } 184 if (isSpecialType != null) { 185 isSpecialType.value = false; 186 } 187 188 key = AsciiUtil.toLowerString(key); 189 type = AsciiUtil.toLowerString(type); 190 191 KeyData keyData = KEYMAP.get(key); 192 if (keyData != null) { 193 if (isKnownKey != null) { 194 isKnownKey.value = Boolean.TRUE; 195 } 196 Type t = keyData.typeMap.get(type); 197 if (t != null) { 198 return t.legacyId; 199 } 200 if (keyData.specialTypes != null) { 201 for (SpecialType st : keyData.specialTypes) { 202 if (st.handler.isWellFormed(type)) { 203 if (isSpecialType != null) { 204 isSpecialType.value = true; 205 } 206 return st.handler.canonicalize(type); 207 } 208 } 209 } 210 } 211 return null; 212 } 213 214 private static void initFromResourceBundle() { 215 UResourceBundle keyTypeDataRes = UResourceBundle.getBundleInstance( 216 ICUData.ICU_BASE_NAME, 217 "keyTypeData", 218 ICUResourceBundle.ICU_DATA_CLASS_LOADER); 219 220 getKeyInfo(keyTypeDataRes.get("keyInfo")); 221 getTypeInfo(keyTypeDataRes.get("typeInfo")); 222 223 UResourceBundle keyMapRes = keyTypeDataRes.get("keyMap"); 224 UResourceBundle typeMapRes = keyTypeDataRes.get("typeMap"); 225 226 // alias data is optional 227 UResourceBundle typeAliasRes = null; 228 UResourceBundle bcpTypeAliasRes = null; 229 230 try { 231 typeAliasRes = keyTypeDataRes.get("typeAlias"); 232 } catch (MissingResourceException e) { 233 // fall through 234 } 235 236 try { 237 bcpTypeAliasRes = keyTypeDataRes.get("bcpTypeAlias"); 238 } catch (MissingResourceException e) { 239 // fall through 240 } 241 242 // iterate through keyMap resource 243 UResourceBundleIterator keyMapItr = keyMapRes.getIterator(); 244 Map<String,Set<String>> _Bcp47Keys = new LinkedHashMap<String,Set<String>>(); 245 246 while (keyMapItr.hasNext()) { 247 UResourceBundle keyMapEntry = keyMapItr.next(); 248 String legacyKeyId = keyMapEntry.getKey(); 249 String bcpKeyId = keyMapEntry.getString(); 250 251 boolean hasSameKey = false; 252 if (bcpKeyId.length() == 0) { 253 // Empty value indicates that BCP key is same with the legacy key. 254 bcpKeyId = legacyKeyId; 255 hasSameKey = true; 256 } 257 final LinkedHashSet<String> _bcp47Types = new LinkedHashSet<String>(); 258 _Bcp47Keys.put(bcpKeyId, Collections.unmodifiableSet(_bcp47Types)); 259 260 boolean isTZ = legacyKeyId.equals("timezone"); 261 262 // reverse type alias map 263 Map<String, Set<String>> typeAliasMap = null; 264 if (typeAliasRes != null) { 265 UResourceBundle typeAliasResByKey = null; 266 try { 267 typeAliasResByKey = typeAliasRes.get(legacyKeyId); 268 } catch (MissingResourceException e) { 269 // fall through 270 } 271 if (typeAliasResByKey != null) { 272 typeAliasMap = new HashMap<String, Set<String>>(); 273 UResourceBundleIterator typeAliasResItr = typeAliasResByKey.getIterator(); 274 while (typeAliasResItr.hasNext()) { 275 UResourceBundle typeAliasDataEntry = typeAliasResItr.next(); 276 String from = typeAliasDataEntry.getKey(); 277 String to = typeAliasDataEntry.getString(); 278 if (isTZ) { 279 from = from.replace(':', '/'); 280 } 281 Set<String> aliasSet = typeAliasMap.get(to); 282 if (aliasSet == null) { 283 aliasSet = new HashSet<String>(); 284 typeAliasMap.put(to, aliasSet); 285 } 286 aliasSet.add(from); 287 } 288 } 289 } 290 291 // reverse bcp type alias map 292 Map<String, Set<String>> bcpTypeAliasMap = null; 293 if (bcpTypeAliasRes != null) { 294 UResourceBundle bcpTypeAliasResByKey = null; 295 try { 296 bcpTypeAliasResByKey = bcpTypeAliasRes.get(bcpKeyId); 297 } catch (MissingResourceException e) { 298 // fall through 299 } 300 if (bcpTypeAliasResByKey != null) { 301 bcpTypeAliasMap = new HashMap<String, Set<String>>(); 302 UResourceBundleIterator bcpTypeAliasResItr = bcpTypeAliasResByKey.getIterator(); 303 while (bcpTypeAliasResItr.hasNext()) { 304 UResourceBundle bcpTypeAliasDataEntry = bcpTypeAliasResItr.next(); 305 String from = bcpTypeAliasDataEntry.getKey(); 306 String to = bcpTypeAliasDataEntry.getString(); 307 Set<String> aliasSet = bcpTypeAliasMap.get(to); 308 if (aliasSet == null) { 309 aliasSet = new HashSet<String>(); 310 bcpTypeAliasMap.put(to, aliasSet); 311 } 312 aliasSet.add(from); 313 } 314 } 315 } 316 317 Map<String, Type> typeDataMap = new HashMap<String, Type>(); 318 EnumSet<SpecialType> specialTypeSet = null; 319 320 // look up type map for the key, and walk through the mapping data 321 UResourceBundle typeMapResByKey = null; 322 try { 323 typeMapResByKey = typeMapRes.get(legacyKeyId); 324 } catch (MissingResourceException e) { 325 // type map for each key must exist 326 assert false; 327 } 328 if (typeMapResByKey != null) { 329 UResourceBundleIterator typeMapResByKeyItr = typeMapResByKey.getIterator(); 330 while (typeMapResByKeyItr.hasNext()) { 331 UResourceBundle typeMapEntry = typeMapResByKeyItr.next(); 332 String legacyTypeId = typeMapEntry.getKey(); 333 String bcpTypeId = typeMapEntry.getString(); 334 335 // special types 336 final char first = legacyTypeId.charAt(0); 337 final boolean isSpecialType = '9' < first && first < 'a' && bcpTypeId.length() == 0; 338 if (isSpecialType) { 339 if (specialTypeSet == null) { 340 specialTypeSet = EnumSet.noneOf(SpecialType.class); 341 } 342 specialTypeSet.add(SpecialType.valueOf(legacyTypeId)); 343 _bcp47Types.add(legacyTypeId); 344 continue; 345 } 346 347 if (isTZ) { 348 // a timezone key uses a colon instead of a slash in the resource. 349 // e.g. America:Los_Angeles 350 legacyTypeId = legacyTypeId.replace(':', '/'); 351 } 352 353 boolean hasSameType = false; 354 if (bcpTypeId.length() == 0) { 355 // Empty value indicates that BCP type is same with the legacy type. 356 bcpTypeId = legacyTypeId; 357 hasSameType = true; 358 } 359 _bcp47Types.add(bcpTypeId); 360 361 // Note: legacy type value should never be 362 // equivalent to bcp type value of a different 363 // type under the same key. So we use a single 364 // map for lookup. 365 Type t = new Type(legacyTypeId, bcpTypeId); 366 typeDataMap.put(AsciiUtil.toLowerString(legacyTypeId), t); 367 if (!hasSameType) { 368 typeDataMap.put(AsciiUtil.toLowerString(bcpTypeId), t); 369 } 370 371 // Also put aliases in the map 372 if (typeAliasMap != null) { 373 Set<String> typeAliasSet = typeAliasMap.get(legacyTypeId); 374 if (typeAliasSet != null) { 375 for (String alias : typeAliasSet) { 376 typeDataMap.put(AsciiUtil.toLowerString(alias), t); 377 } 378 } 379 } 380 if (bcpTypeAliasMap != null) { 381 Set<String> bcpTypeAliasSet = bcpTypeAliasMap.get(bcpTypeId); 382 if (bcpTypeAliasSet != null) { 383 for (String alias : bcpTypeAliasSet) { 384 typeDataMap.put(AsciiUtil.toLowerString(alias), t); 385 } 386 } 387 } 388 } 389 } 390 391 KeyData keyData = new KeyData(legacyKeyId, bcpKeyId, typeDataMap, specialTypeSet); 392 393 KEYMAP.put(AsciiUtil.toLowerString(legacyKeyId), keyData); 394 if (!hasSameKey) { 395 KEYMAP.put(AsciiUtil.toLowerString(bcpKeyId), keyData); 396 } 397 } 398 BCP47_KEYS = Collections.unmodifiableMap(_Bcp47Keys); 399 } 400 401 static Set<String> DEPRECATED_KEYS = Collections.emptySet(); // default for no resources 402 static Map<String, ValueType> VALUE_TYPES = Collections.emptyMap(); // default for no resources 403 static Map<String, Set<String>> DEPRECATED_KEY_TYPES = Collections.emptyMap(); // default for no resources 404 405 private enum KeyInfoType {deprecated, valueType} 406 private enum TypeInfoType {deprecated} 407 408 /** Reads 409keyInfo{ 410 deprecated{ 411 kh{"true"} 412 vt{"true"} 413 } 414 valueType{ 415 ca{"incremental"} 416 kr{"multiple"} 417 vt{"multiple"} 418 x0{"any"} 419 } 420} 421 */ 422 private static void getKeyInfo(UResourceBundle keyInfoRes) { 423 Set<String> _deprecatedKeys = new LinkedHashSet<String>(); 424 Map<String, ValueType> _valueTypes = new LinkedHashMap<String, ValueType>(); 425 for (UResourceBundleIterator keyInfoIt = keyInfoRes.getIterator(); keyInfoIt.hasNext();) { 426 UResourceBundle keyInfoEntry = keyInfoIt.next(); 427 String key = keyInfoEntry.getKey(); 428 KeyInfoType keyInfo = KeyInfoType.valueOf(key); 429 for (UResourceBundleIterator keyInfoIt2 = keyInfoEntry.getIterator(); keyInfoIt2.hasNext();) { 430 UResourceBundle keyInfoEntry2 = keyInfoIt2.next(); 431 String key2 = keyInfoEntry2.getKey(); 432 String value2 = keyInfoEntry2.getString(); 433 switch (keyInfo) { 434 case deprecated: 435 _deprecatedKeys.add(key2); 436 break; 437 case valueType: 438 _valueTypes.put(key2, ValueType.valueOf(value2)); 439 break; 440 } 441 } 442 } 443 DEPRECATED_KEYS = Collections.unmodifiableSet(_deprecatedKeys); 444 VALUE_TYPES = Collections.unmodifiableMap(_valueTypes); 445 } 446 447 /** Reads: 448typeInfo{ 449 deprecated{ 450 co{ 451 direct{"true"} 452 } 453 tz{ 454 camtr{"true"} 455 } 456 } 457} 458 */ 459 private static void getTypeInfo(UResourceBundle typeInfoRes) { 460 Map<String,Set<String>> _deprecatedKeyTypes = new LinkedHashMap<String,Set<String>>(); 461 for (UResourceBundleIterator keyInfoIt = typeInfoRes.getIterator(); keyInfoIt.hasNext();) { 462 UResourceBundle keyInfoEntry = keyInfoIt.next(); 463 String key = keyInfoEntry.getKey(); 464 TypeInfoType typeInfo = TypeInfoType.valueOf(key); 465 for (UResourceBundleIterator keyInfoIt2 = keyInfoEntry.getIterator(); keyInfoIt2.hasNext();) { 466 UResourceBundle keyInfoEntry2 = keyInfoIt2.next(); 467 String key2 = keyInfoEntry2.getKey(); 468 Set<String> _deprecatedTypes = new LinkedHashSet<String>(); 469 for (UResourceBundleIterator keyInfoIt3 = keyInfoEntry2.getIterator(); keyInfoIt3.hasNext();) { 470 UResourceBundle keyInfoEntry3 = keyInfoIt3.next(); 471 String key3 = keyInfoEntry3.getKey(); 472 switch (typeInfo) { // allow for expansion 473 case deprecated: 474 _deprecatedTypes.add(key3); 475 break; 476 } 477 } 478 _deprecatedKeyTypes.put(key2, Collections.unmodifiableSet(_deprecatedTypes)); 479 } 480 } 481 DEPRECATED_KEY_TYPES = Collections.unmodifiableMap(_deprecatedKeyTypes); 482 } 483 484 // 485 // Note: The key-type data is currently read from ICU resource bundle keyTypeData.res. 486 // In future, we may import the data into code like below directly from CLDR to 487 // avoid cyclic dependency between ULocale and UResourceBundle. For now, the code 488 // below is just for proof of concept, and commented out. 489 // 490 491 // private static final String[][] TYPE_DATA_CA = { 492 // // {<legacy type>, <bcp type - if different>}, 493 // {"buddhist", null}, 494 // {"chinese", null}, 495 // {"coptic", null}, 496 // {"dangi", null}, 497 // {"ethiopic", null}, 498 // {"ethiopic-amete-alem", "ethioaa"}, 499 // {"gregorian", "gregory"}, 500 // {"hebrew", null}, 501 // {"indian", null}, 502 // {"islamic", null}, 503 // {"islamic-civil", null}, 504 // {"islamic-rgsa", null}, 505 // {"islamic-tbla", null}, 506 // {"islamic-umalqura", null}, 507 // {"iso8601", null}, 508 // {"japanese", null}, 509 // {"persian", null}, 510 // {"roc", null}, 511 // }; 512 // 513 // private static final String[][] TYPE_DATA_KS = { 514 // // {<legacy type>, <bcp type - if different>}, 515 // {"identical", "identic"}, 516 // {"primary", "level1"}, 517 // {"quaternary", "level4"}, 518 // {"secondary", "level2"}, 519 // {"tertiary", "level3"}, 520 // }; 521 // 522 // private static final String[][] TYPE_ALIAS_KS = { 523 // // {<legacy alias>, <legacy canonical>}, 524 // {"quarternary", "quaternary"}, 525 // }; 526 // 527 // private static final String[][] BCP_TYPE_ALIAS_CA = { 528 // // {<bcp deprecated>, <bcp preferred> 529 // {"islamicc", "islamic-civil"}, 530 // }; 531 // 532 // private static final Object[][] KEY_DATA = { 533 // // {<legacy key>, <bcp key - if different>, <type map>, <type alias>, <bcp type alias>}, 534 // {"calendar", "ca", TYPE_DATA_CA, null, BCP_TYPE_ALIAS_CA}, 535 // {"colstrength", "ks", TYPE_DATA_KS, TYPE_ALIAS_KS, null}, 536 // }; 537 538 private static final Object[][] KEY_DATA = {}; 539 540 @SuppressWarnings("unused") 541 private static void initFromTables() { 542 for (Object[] keyDataEntry : KEY_DATA) { 543 String legacyKeyId = (String)keyDataEntry[0]; 544 String bcpKeyId = (String)keyDataEntry[1]; 545 String[][] typeData = (String[][])keyDataEntry[2]; 546 String[][] typeAliasData = (String[][])keyDataEntry[3]; 547 String[][] bcpTypeAliasData = (String[][])keyDataEntry[4]; 548 549 boolean hasSameKey = false; 550 if (bcpKeyId == null) { 551 bcpKeyId = legacyKeyId; 552 hasSameKey = true; 553 } 554 555 // reverse type alias map 556 Map<String, Set<String>> typeAliasMap = null; 557 if (typeAliasData != null) { 558 typeAliasMap = new HashMap<String, Set<String>>(); 559 for (String[] typeAliasDataEntry : typeAliasData) { 560 String from = typeAliasDataEntry[0]; 561 String to = typeAliasDataEntry[1]; 562 Set<String> aliasSet = typeAliasMap.get(to); 563 if (aliasSet == null) { 564 aliasSet = new HashSet<String>(); 565 typeAliasMap.put(to, aliasSet); 566 } 567 aliasSet.add(from); 568 } 569 } 570 571 // BCP type alias map data 572 Map<String, Set<String>> bcpTypeAliasMap = null; 573 if (bcpTypeAliasData != null) { 574 bcpTypeAliasMap = new HashMap<String, Set<String>>(); 575 for (String[] bcpTypeAliasDataEntry : bcpTypeAliasData) { 576 String from = bcpTypeAliasDataEntry[0]; 577 String to = bcpTypeAliasDataEntry[1]; 578 Set<String> aliasSet = bcpTypeAliasMap.get(to); 579 if (aliasSet == null) { 580 aliasSet = new HashSet<String>(); 581 bcpTypeAliasMap.put(to, aliasSet); 582 } 583 aliasSet.add(from); 584 } 585 } 586 587 // Type map data 588 assert typeData != null; 589 Map<String, Type> typeDataMap = new HashMap<String, Type>(); 590 Set<SpecialType> specialTypeSet = null; 591 592 for (String[] typeDataEntry : typeData) { 593 String legacyTypeId = typeDataEntry[0]; 594 String bcpTypeId = typeDataEntry[1]; 595 596 // special types 597 boolean isSpecialType = false; 598 for (SpecialType st : SpecialType.values()) { 599 if (legacyTypeId.equals(st.toString())) { 600 isSpecialType = true; 601 if (specialTypeSet == null) { 602 specialTypeSet = new HashSet<SpecialType>(); 603 } 604 specialTypeSet.add(st); 605 break; 606 } 607 } 608 if (isSpecialType) { 609 continue; 610 } 611 612 boolean hasSameType = false; 613 if (bcpTypeId == null) { 614 bcpTypeId = legacyTypeId; 615 hasSameType = true; 616 } 617 618 // Note: legacy type value should never be 619 // equivalent to bcp type value of a different 620 // type under the same key. So we use a single 621 // map for lookup. 622 Type t = new Type(legacyTypeId, bcpTypeId); 623 typeDataMap.put(AsciiUtil.toLowerString(legacyTypeId), t); 624 if (!hasSameType) { 625 typeDataMap.put(AsciiUtil.toLowerString(bcpTypeId), t); 626 } 627 628 // Also put aliases in the index 629 Set<String> typeAliasSet = typeAliasMap.get(legacyTypeId); 630 if (typeAliasSet != null) { 631 for (String alias : typeAliasSet) { 632 typeDataMap.put(AsciiUtil.toLowerString(alias), t); 633 } 634 } 635 Set<String> bcpTypeAliasSet = bcpTypeAliasMap.get(bcpTypeId); 636 if (bcpTypeAliasSet != null) { 637 for (String alias : bcpTypeAliasSet) { 638 typeDataMap.put(AsciiUtil.toLowerString(alias), t); 639 } 640 } 641 } 642 643 EnumSet<SpecialType> specialTypes = null; 644 if (specialTypeSet != null) { 645 specialTypes = EnumSet.copyOf(specialTypeSet); 646 } 647 648 KeyData keyData = new KeyData(legacyKeyId, bcpKeyId, typeDataMap, specialTypes); 649 650 KEYMAP.put(AsciiUtil.toLowerString(legacyKeyId), keyData); 651 if (!hasSameKey) { 652 KEYMAP.put(AsciiUtil.toLowerString(bcpKeyId), keyData); 653 } 654 } 655 } 656 657 private static final Map<String, KeyData> KEYMAP = new HashMap<String, KeyData>(); 658 private static Map<String, Set<String>> BCP47_KEYS; 659 660 static { 661 // initFromTables(); 662 initFromResourceBundle(); 663 } 664 665 public static Set<String> getBcp47Keys() { 666 return BCP47_KEYS.keySet(); 667 }; 668 669 public static Set<String> getBcp47KeyTypes(String key) { 670 return BCP47_KEYS.get(key); 671 }; 672 673 public static boolean isDeprecated(String key) { 674 return DEPRECATED_KEYS.contains(key); 675 } 676 677 public static boolean isDeprecated(String key, String type) { 678 Set<String> deprecatedTypes = DEPRECATED_KEY_TYPES.get(key); 679 if (deprecatedTypes == null) { 680 return false; 681 } 682 return deprecatedTypes.contains(type); 683 } 684 685 public static ValueType getValueType(String key) { 686 ValueType type = VALUE_TYPES.get(key); 687 return type == null ? ValueType.single : type; 688 } 689} 690