make/tools/src/build/tools/cldrconverter/Bundle.java

Print this page




  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  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 build.tools.cldrconverter;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.EnumSet;
  31 import java.util.HashMap;

  32 import java.util.List;
  33 import java.util.Map;
  34 
  35 class Bundle {
  36     static enum Type {
  37         LOCALENAMES, CURRENCYNAMES, TIMEZONENAMES, CALENDARDATA, FORMATDATA;
  38 
  39         static EnumSet<Type> ALL_TYPES = EnumSet.of(LOCALENAMES,
  40                                                     CURRENCYNAMES,
  41                                                     TIMEZONENAMES,
  42                                                     CALENDARDATA,
  43                                                     FORMATDATA);
  44     }
  45 
  46     private final static Map<String, Bundle> bundles = new HashMap<>();
  47 
  48     private final static String[] NUMBER_PATTERN_KEYS = {
  49         "NumberPatterns/decimal",
  50         "NumberPatterns/currency",
  51         "NumberPatterns/percent"


  69         "DateTimePatterns/full-time",
  70         "DateTimePatterns/long-time",
  71         "DateTimePatterns/medium-time",
  72         "DateTimePatterns/short-time",
  73     };
  74 
  75     private final static String[] DATE_PATTERN_KEYS = {
  76         "DateTimePatterns/full-date",
  77         "DateTimePatterns/long-date",
  78         "DateTimePatterns/medium-date",
  79         "DateTimePatterns/short-date",
  80     };
  81 
  82     private final static String[] DATETIME_PATTERN_KEYS = {
  83         "DateTimePatterns/date-time"
  84     };
  85 
  86     private final static String[] ERA_KEYS = {
  87         "long.Eras",
  88         "Eras",
  89         "short.Eras"
















  90     };
  91 
  92     private final String id;
  93     private final String cldrPath;
  94     private final EnumSet<Type> bundleTypes;
  95     private final String currencies;
  96 
  97     static Bundle getBundle(String id) {
  98         return bundles.get(id);
  99     }
 100 

 101     Bundle(String id, String cldrPath, String bundles, String currencies) {
 102         this.id = id;
 103         this.cldrPath = cldrPath;
 104         if ("localenames".equals(bundles)) {
 105             bundleTypes = EnumSet.of(Type.LOCALENAMES);
 106         } else if ("currencynames".equals(bundles)) {
 107             bundleTypes = EnumSet.of(Type.CURRENCYNAMES);
 108         } else {
 109             bundleTypes = Type.ALL_TYPES;
 110         }
 111         if (currencies == null) {
 112             currencies = "local";
 113         }
 114         this.currencies = currencies;
 115         addBundle();
 116     }
 117 
 118     private void addBundle() {
 119         Bundle.bundles.put(id, this);
 120     }


 225                             }
 226                         }
 227                         numberElements[i] = value;
 228                     }
 229                     myMap.put(script + "." + "NumberElements", numberElements);
 230                     break;
 231                 }
 232             }
 233         }
 234 
 235         // another hack: parentsMap is not used for date-time resources.
 236         if ("root".equals(id)) {
 237             parentsMap = null;
 238         }
 239 
 240         for (CalendarType calendarType : CalendarType.values()) {
 241             String calendarPrefix = calendarType.keyElementName();
 242             // handle multiple inheritance for month and day names
 243             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthNames");
 244             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthAbbreviations");

 245             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayNames");
 246             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayAbbreviations");

 247             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "AmPmMarkers");

 248 
 249             adjustEraNames(myMap, calendarType);
 250 
 251             handleDateTimeFormatPatterns(TIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "TimePatterns");
 252             handleDateTimeFormatPatterns(DATE_PATTERN_KEYS, myMap, parentsMap, calendarType, "DatePatterns");
 253             handleDateTimeFormatPatterns(DATETIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "DateTimePatterns");
 254         }
 255 





























































































 256         return myMap;
 257     }
 258 
 259     private void handleMultipleInheritance(Map<String, Object> map, Map<String, Object> parents, String key) {
 260         String formatKey = key + "/format";
 261         Object format = map.get(formatKey);
 262         if (format != null) {
 263             map.remove(formatKey);
 264             map.put(key, format);
 265             if (fillInElements(parents, formatKey, format)) {
 266                 map.remove(key);
 267             }
 268         }
 269         String standaloneKey = key + "/stand-alone";
 270         Object standalone = map.get(standaloneKey);
 271         if (standalone != null) {
 272             map.remove(standaloneKey);
 273             String realKey = key;
 274             if (format != null) {
 275                 realKey = "standalone." + key;


 335                         } else {
 336                             newValue[0] = "";
 337                         }
 338                         System.arraycopy(value, 0, newValue, 1, value.length);
 339                         value = newValue;
 340                     }
 341                     break;
 342 
 343                 case BUDDHIST:
 344                     // Replace the value
 345                     value = new String[] {"BC", value[0]};
 346                     break;
 347                 }
 348                 if (!key.equals(realKey)) {
 349                     map.put(realKey, value);
 350                 }
 351             }
 352             realKeys[index] = realKey;
 353             eraNames[index++] = value;
 354         }
 355         if (eraNames[0] != null) {
 356             if (eraNames[1] != null) {
 357                 if (eraNames[2] == null) {
 358                     // Eras -> short.Eras
 359                     // long.Eras -> Eras
 360                     map.put(realKeys[2], map.get(realKeys[1]));
 361                     map.put(realKeys[1], map.get(realKeys[0]));
 362                 }
 363             } else {
 364                 // long.Eras -> Eras
 365                 map.put(realKeys[1], map.get(realKeys[0]));
 366             }
 367             // remove long.Eras
 368             map.remove(realKeys[0]);
 369         }
 370     }
 371 
 372     private void handleDateTimeFormatPatterns(String[] patternKeys, Map<String, Object> myMap, Map<String, Object> parentsMap,
 373                                               CalendarType calendarType, String name) {
 374         String calendarPrefix = calendarType.keyElementName();
 375         for (String k : patternKeys) {
 376             if (myMap.containsKey(calendarPrefix + k)) {
 377                 int len = patternKeys.length;
 378                 List<String> patterns = new ArrayList<>();
 379                 for (int i = 0; i < len; i++) {
 380                     String key = calendarPrefix + patternKeys[i];
 381                     String pattern = (String) myMap.remove(key);
 382                     if (pattern == null) {
 383                         pattern = (String) parentsMap.remove(key);
 384                     }
 385                     if (pattern != null) {
 386                         patterns.add(i, translateDateFormatLetters(calendarType, pattern));
 387                     }
 388                 }


 456                 continue;
 457             }
 458             convert(calendarType, lastLetter, count, jrePattern);
 459             lastLetter = c;
 460             count = 1;
 461         }
 462 
 463         if (inQuote) {
 464             throw new InternalError("Unterminated quote in date-time pattern: " + cldrFormat);
 465         }
 466 
 467         if (count != 0) {
 468             convert(calendarType, lastLetter, count, jrePattern);
 469         }
 470         if (cldrFormat.contentEquals(jrePattern)) {
 471             return cldrFormat;
 472         }
 473         return jrePattern.toString();
 474     }
 475 
















































































 476     private void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) {
 477         switch (cldrLetter) {
 478         case 'G':
 479             if (calendarType != CalendarType.GREGORIAN) {
 480                 // Adjust the number of 'G's for JRE SimpleDateFormat
 481                 if (count == 5) {
 482                     // CLDR narrow -> JRE short
 483                     count = 1;
 484                 } else if (count == 1) {
 485                     // CLDR abbr -> JRE long
 486                     count = 4;
 487                 }
 488             }
 489             appendN(cldrLetter, count, sb);
 490             break;
 491 
 492         // TODO: support 'c' and 'e' in JRE SimpleDateFormat
 493         // Use 'u' and 'E' for now.
 494         case 'c':
 495         case 'e':


 521         case 'u':
 522         case 'U':
 523         case 'q':
 524         case 'Q':
 525         case 'l':
 526         case 'g':
 527         case 'j':
 528         case 'A':
 529             throw new InternalError(String.format("Unsupported letter: '%c', count=%d%n",
 530                                                   cldrLetter, count));
 531         default:
 532             appendN(cldrLetter, count, sb);
 533             break;
 534         }
 535     }
 536 
 537     private void appendN(char c, int n, StringBuilder sb) {
 538         for (int i = 0; i < n; i++) {
 539             sb.append(c);
 540         }









 541     }
 542 }


  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  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 build.tools.cldrconverter;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.EnumSet;
  31 import java.util.HashMap;
  32 import java.util.Iterator;
  33 import java.util.List;
  34 import java.util.Map;
  35 
  36 class Bundle {
  37     static enum Type {
  38         LOCALENAMES, CURRENCYNAMES, TIMEZONENAMES, CALENDARDATA, FORMATDATA;
  39 
  40         static EnumSet<Type> ALL_TYPES = EnumSet.of(LOCALENAMES,
  41                                                     CURRENCYNAMES,
  42                                                     TIMEZONENAMES,
  43                                                     CALENDARDATA,
  44                                                     FORMATDATA);
  45     }
  46 
  47     private final static Map<String, Bundle> bundles = new HashMap<>();
  48 
  49     private final static String[] NUMBER_PATTERN_KEYS = {
  50         "NumberPatterns/decimal",
  51         "NumberPatterns/currency",
  52         "NumberPatterns/percent"


  70         "DateTimePatterns/full-time",
  71         "DateTimePatterns/long-time",
  72         "DateTimePatterns/medium-time",
  73         "DateTimePatterns/short-time",
  74     };
  75 
  76     private final static String[] DATE_PATTERN_KEYS = {
  77         "DateTimePatterns/full-date",
  78         "DateTimePatterns/long-date",
  79         "DateTimePatterns/medium-date",
  80         "DateTimePatterns/short-date",
  81     };
  82 
  83     private final static String[] DATETIME_PATTERN_KEYS = {
  84         "DateTimePatterns/date-time"
  85     };
  86 
  87     private final static String[] ERA_KEYS = {
  88         "long.Eras",
  89         "Eras",
  90         "narrow.Eras"
  91     };
  92 
  93     // Keys for individual time zone names
  94     private final static String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long";
  95     private final static String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short";
  96     private final static String TZ_STD_LONG_KEY = "timezone.displayname.standard.long";
  97     private final static String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short";
  98     private final static String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long";
  99     private final static String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short";
 100     private final static String[] ZONE_NAME_KEYS = {
 101         TZ_STD_LONG_KEY,
 102         TZ_STD_SHORT_KEY,
 103         TZ_DST_LONG_KEY,
 104         TZ_DST_SHORT_KEY,
 105         TZ_GEN_LONG_KEY,
 106         TZ_GEN_SHORT_KEY
 107     };
 108 
 109     private final String id;
 110     private final String cldrPath;
 111     private final EnumSet<Type> bundleTypes;
 112     private final String currencies;
 113 
 114     static Bundle getBundle(String id) {
 115         return bundles.get(id);
 116     }
 117 
 118     @SuppressWarnings("ConvertToStringSwitch")
 119     Bundle(String id, String cldrPath, String bundles, String currencies) {
 120         this.id = id;
 121         this.cldrPath = cldrPath;
 122         if ("localenames".equals(bundles)) {
 123             bundleTypes = EnumSet.of(Type.LOCALENAMES);
 124         } else if ("currencynames".equals(bundles)) {
 125             bundleTypes = EnumSet.of(Type.CURRENCYNAMES);
 126         } else {
 127             bundleTypes = Type.ALL_TYPES;
 128         }
 129         if (currencies == null) {
 130             currencies = "local";
 131         }
 132         this.currencies = currencies;
 133         addBundle();
 134     }
 135 
 136     private void addBundle() {
 137         Bundle.bundles.put(id, this);
 138     }


 243                             }
 244                         }
 245                         numberElements[i] = value;
 246                     }
 247                     myMap.put(script + "." + "NumberElements", numberElements);
 248                     break;
 249                 }
 250             }
 251         }
 252 
 253         // another hack: parentsMap is not used for date-time resources.
 254         if ("root".equals(id)) {
 255             parentsMap = null;
 256         }
 257 
 258         for (CalendarType calendarType : CalendarType.values()) {
 259             String calendarPrefix = calendarType.keyElementName();
 260             // handle multiple inheritance for month and day names
 261             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthNames");
 262             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthAbbreviations");
 263             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthNarrows");
 264             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayNames");
 265             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayAbbreviations");
 266             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayNarrows");
 267             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "AmPmMarkers");
 268             handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "narrow.AmPmMarkers");
 269 
 270             adjustEraNames(myMap, calendarType);
 271 
 272             handleDateTimeFormatPatterns(TIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "TimePatterns");
 273             handleDateTimeFormatPatterns(DATE_PATTERN_KEYS, myMap, parentsMap, calendarType, "DatePatterns");
 274             handleDateTimeFormatPatterns(DATETIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "DateTimePatterns");
 275         }
 276 
 277         // if myMap has any empty timezone or metazone names, weed out them.
 278         // Fill in any missing abbreviations if locale is "en".
 279         for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) {
 280             String key = it.next();
 281             if (key.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX)
 282                     || key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) {
 283                 @SuppressWarnings("unchecked")
 284                 Map<String, String> nameMap = (Map<String, String>) myMap.get(key);
 285                 if (nameMap.isEmpty()) {
 286                     // Some zones have only exemplarCity, which become empty.
 287                     // Remove those from the map.
 288                     it.remove();
 289                     continue;
 290                 }
 291 
 292                 if (id.startsWith("en")) {
 293                     fillInAbbrs(key, nameMap);
 294                 }
 295             }
 296         }
 297         for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) {
 298             String key = it.next();
 299             if (key.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX)
 300                     || key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) {
 301                 @SuppressWarnings("unchecked")
 302                 Map<String, String> nameMap = (Map<String, String>) myMap.get(key);
 303                 // Convert key/value pairs to an array.
 304                 String[] names = new String[ZONE_NAME_KEYS.length];
 305                 int ix = 0;
 306                 for (String nameKey : ZONE_NAME_KEYS) {
 307                     String name = nameMap.get(nameKey);
 308                     if (name == null) {
 309                         @SuppressWarnings("unchecked")
 310                         Map<String, String> parentNames = (Map<String, String>) parentsMap.get(key);
 311                         if (parentNames != null) {
 312                             name = parentNames.get(nameKey);
 313                         }
 314                     }
 315                     names[ix++] = name;
 316                 }
 317                 if (hasNulls(names)) {
 318                     String metaKey = toMetaZoneKey(key);
 319                     if (metaKey != null) {
 320                         Object obj = myMap.get(metaKey);
 321                         if (obj instanceof String[]) {
 322                             String[] metaNames = (String[]) obj;
 323                             for (int i = 0; i < names.length; i++) {
 324                                 if (names[i] == null) {
 325                                     names[i] = metaNames[i];
 326                                 }
 327                             }
 328                         } else if (obj instanceof Map) {
 329                             @SuppressWarnings("unchecked")
 330                             Map<String, String> m = (Map<String, String>) obj;
 331                             for (int i = 0; i < names.length; i++) {
 332                                 if (names[i] == null) {
 333                                     names[i] = m.get(ZONE_NAME_KEYS[i]);
 334                                 }
 335                             }
 336                         }
 337                     }
 338                     // If there are still any nulls, try filling in them from en data.
 339                     if (hasNulls(names) && !id.equals("en")) {
 340                         @SuppressWarnings("unchecked")
 341                         String[] enNames = (String[]) Bundle.getBundle("en").getTargetMap().get(key);
 342                         if (enNames == null) {
 343                             if (metaKey != null) {
 344                                 @SuppressWarnings("unchecked")
 345                                 String[] metaNames = (String[]) Bundle.getBundle("en").getTargetMap().get(metaKey);
 346                                 enNames = metaNames;
 347                             }
 348                         }
 349                         if (enNames != null) {
 350                             for (int i = 0; i < names.length; i++) {
 351                                 if (names[i] == null) {
 352                                     names[i] = enNames[i];
 353                                 }
 354                             }
 355                         }
 356                         // If there are still nulls, give up names.
 357                         if (hasNulls(names)) {
 358                             names = null;
 359                         }
 360                     }
 361                 }
 362                 // replace the Map with the array
 363                 if (names != null) {
 364                     myMap.put(key, names);
 365                 } else {
 366                     it.remove();
 367                 }
 368             }
 369         }
 370         return myMap;
 371     }
 372 
 373     private void handleMultipleInheritance(Map<String, Object> map, Map<String, Object> parents, String key) {
 374         String formatKey = key + "/format";
 375         Object format = map.get(formatKey);
 376         if (format != null) {
 377             map.remove(formatKey);
 378             map.put(key, format);
 379             if (fillInElements(parents, formatKey, format)) {
 380                 map.remove(key);
 381             }
 382         }
 383         String standaloneKey = key + "/stand-alone";
 384         Object standalone = map.get(standaloneKey);
 385         if (standalone != null) {
 386             map.remove(standaloneKey);
 387             String realKey = key;
 388             if (format != null) {
 389                 realKey = "standalone." + key;


 449                         } else {
 450                             newValue[0] = "";
 451                         }
 452                         System.arraycopy(value, 0, newValue, 1, value.length);
 453                         value = newValue;
 454                     }
 455                     break;
 456 
 457                 case BUDDHIST:
 458                     // Replace the value
 459                     value = new String[] {"BC", value[0]};
 460                     break;
 461                 }
 462                 if (!key.equals(realKey)) {
 463                     map.put(realKey, value);
 464                 }
 465             }
 466             realKeys[index] = realKey;
 467             eraNames[index++] = value;
 468         }
 469         for (int i = 0; i < eraNames.length; i++) {
 470             if (eraNames[i] == null) {
 471                 map.put(realKeys[i], null);




 472             }






 473         }
 474     }
 475 
 476     private void handleDateTimeFormatPatterns(String[] patternKeys, Map<String, Object> myMap, Map<String, Object> parentsMap,
 477                                               CalendarType calendarType, String name) {
 478         String calendarPrefix = calendarType.keyElementName();
 479         for (String k : patternKeys) {
 480             if (myMap.containsKey(calendarPrefix + k)) {
 481                 int len = patternKeys.length;
 482                 List<String> patterns = new ArrayList<>();
 483                 for (int i = 0; i < len; i++) {
 484                     String key = calendarPrefix + patternKeys[i];
 485                     String pattern = (String) myMap.remove(key);
 486                     if (pattern == null) {
 487                         pattern = (String) parentsMap.remove(key);
 488                     }
 489                     if (pattern != null) {
 490                         patterns.add(i, translateDateFormatLetters(calendarType, pattern));
 491                     }
 492                 }


 560                 continue;
 561             }
 562             convert(calendarType, lastLetter, count, jrePattern);
 563             lastLetter = c;
 564             count = 1;
 565         }
 566 
 567         if (inQuote) {
 568             throw new InternalError("Unterminated quote in date-time pattern: " + cldrFormat);
 569         }
 570 
 571         if (count != 0) {
 572             convert(calendarType, lastLetter, count, jrePattern);
 573         }
 574         if (cldrFormat.contentEquals(jrePattern)) {
 575             return cldrFormat;
 576         }
 577         return jrePattern.toString();
 578     }
 579 
 580     private String toMetaZoneKey(String tzKey) {
 581         if (tzKey.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX)) {
 582             String tz = tzKey.substring(CLDRConverter.TIMEZONE_ID_PREFIX.length());
 583             String meta = CLDRConverter.handlerMetaZones.get(tz);
 584             if (meta != null) {
 585                 return CLDRConverter.METAZONE_ID_PREFIX + meta;
 586             }
 587         }
 588         return null;
 589     }
 590 
 591     private void fillInAbbrs(String key, Map<String, String> map) {
 592         fillInAbbrs(TZ_STD_LONG_KEY, TZ_STD_SHORT_KEY, map);
 593         fillInAbbrs(TZ_DST_LONG_KEY, TZ_DST_SHORT_KEY, map);
 594         fillInAbbrs(TZ_GEN_LONG_KEY, TZ_GEN_SHORT_KEY, map);
 595 
 596         // If the standard std is "Standard Time" and daylight std is "Summer Time",
 597         // replace the standard std with the generic std to avoid using
 598         // the same abbrivation except for Australia time zone names.
 599         String std = map.get(TZ_STD_SHORT_KEY);
 600         String dst = map.get(TZ_DST_SHORT_KEY);
 601         String gen = map.get(TZ_GEN_SHORT_KEY);
 602         if (std != null) {
 603             if (dst == null) {
 604                 // if dst is null, create long and short names from the standard
 605                 // std. ("Something Standard Time" to "Something Daylight Time",
 606                 // or "Something Time" to "Something Summer Time")
 607                 String name = map.get(TZ_STD_LONG_KEY);
 608                 if (name != null) {
 609                     if (name.contains("Standard Time")) {
 610                         name = name.replace("Standard Time", "Daylight Time");
 611                     } else if (name.endsWith("Mean Time")) {
 612                         name = name.replace("Mean Time", "Summer Time");
 613                     } else if (name.endsWith(" Time")) {
 614                         name = name.replace(" Time", " Summer Time");
 615                     }
 616                     map.put(TZ_DST_LONG_KEY, name);
 617                     fillInAbbrs(TZ_DST_LONG_KEY, TZ_DST_SHORT_KEY, map);
 618                 }
 619             }
 620             if (gen  == null) {
 621                 String name = map.get(TZ_STD_LONG_KEY);
 622                 if (name != null) {
 623                     if (name.endsWith("Standard Time")) {
 624                         name = name.replace("Standard Time", "Time");
 625                     } else if (name.endsWith("Mean Time")) {
 626                         name = name.replace("Mean Time", "Time");
 627                     }
 628                     map.put(TZ_GEN_LONG_KEY, name);
 629                     fillInAbbrs(TZ_GEN_LONG_KEY, TZ_GEN_SHORT_KEY, map);
 630                 }
 631             }
 632         }
 633     }
 634 
 635     private void fillInAbbrs(String longKey, String shortKey, Map<String, String> map) {
 636         String abbr = map.get(shortKey);
 637         if (abbr == null) {
 638             String name = map.get(longKey);
 639             if (name != null) {
 640                 abbr = toAbbr(name);
 641                 if (abbr != null) {
 642                     map.put(shortKey, abbr);
 643                 }
 644             }
 645         }
 646     }
 647 
 648     private String toAbbr(String name) {
 649         String[] substrs = name.split("\\s+");
 650         StringBuilder sb = new StringBuilder();
 651         for (String s : substrs) {
 652             char c = s.charAt(0);
 653             if (c >= 'A' && c <= 'Z') {
 654                 sb.append(c);
 655             }
 656         }
 657         return sb.length() > 0 ? sb.toString() : null;
 658     }
 659 
 660     private void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) {
 661         switch (cldrLetter) {
 662         case 'G':
 663             if (calendarType != CalendarType.GREGORIAN) {
 664                 // Adjust the number of 'G's for JRE SimpleDateFormat
 665                 if (count == 5) {
 666                     // CLDR narrow -> JRE short
 667                     count = 1;
 668                 } else if (count == 1) {
 669                     // CLDR abbr -> JRE long
 670                     count = 4;
 671                 }
 672             }
 673             appendN(cldrLetter, count, sb);
 674             break;
 675 
 676         // TODO: support 'c' and 'e' in JRE SimpleDateFormat
 677         // Use 'u' and 'E' for now.
 678         case 'c':
 679         case 'e':


 705         case 'u':
 706         case 'U':
 707         case 'q':
 708         case 'Q':
 709         case 'l':
 710         case 'g':
 711         case 'j':
 712         case 'A':
 713             throw new InternalError(String.format("Unsupported letter: '%c', count=%d%n",
 714                                                   cldrLetter, count));
 715         default:
 716             appendN(cldrLetter, count, sb);
 717             break;
 718         }
 719     }
 720 
 721     private void appendN(char c, int n, StringBuilder sb) {
 722         for (int i = 0; i < n; i++) {
 723             sb.append(c);
 724         }
 725     }
 726 
 727     private static boolean hasNulls(Object[] array) {
 728         for (int i = 0; i < array.length; i++) {
 729             if (array[i] == null) {
 730                 return true;
 731             }
 732         }
 733         return false;
 734     }
 735 }