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