--- /dev/null 2012-11-08 15:50:50.609141041 +0900 +++ new/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java 2012-11-10 09:36:05.000000000 +0900 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.util.locale.provider; + +import static java.util.Calendar.*; +import java.util.Comparator; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.TreeMap; +import java.util.spi.CalendarNameProvider; + +/** + * Concrete implementation of the {@link java.util.spi.CalendarDataProvider + * CalendarDataProvider} class for the JRE LocaleProviderAdapter. + * + * @author Masayoshi Okutsu + * @author Naoto Sato + */ +public class CalendarNameProviderImpl extends CalendarNameProvider implements AvailableLanguageTags { + private final LocaleProviderAdapter.Type type; + private final Set langtags; + + public CalendarNameProviderImpl(LocaleProviderAdapter.Type type, Set langtags) { + this.type = type; + this.langtags = langtags; + } + + @Override + public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) { + String name = null; + String key = getKey(calendarType, field, style); + if (key != null) { + ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); + if (rb.containsKey(key)) { + String[] strings = rb.getStringArray(key); + if (strings.length > 0) { + if (field == DAY_OF_WEEK || field == YEAR) { + --value; + } + name = strings[value]; + // If name is empty in standalone, try its `format' style. + if (name.length() == 0 + && (style == SHORT_STANDALONE || style == LONG_STANDALONE)) { + name = getDisplayName(calendarType, field, value, + style == SHORT_STANDALONE ? SHORT_FORMAT : LONG_FORMAT, + locale); + } + } + } + } + return name; + } + + @Override + public Map getDisplayNames(String calendarType, int field, int style, Locale locale) { + Map names; + if (style == ALL_STYLES) { + names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale); + if (field != AM_PM) { + for (int st : new int[] { SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE }) { + names.putAll(getDisplayNamesImpl(calendarType, field, st, locale)); + } + } + } else { + // specific style + names = getDisplayNamesImpl(calendarType, field, style, locale); + } + return names.isEmpty() ? null : names; + } + + private Map getDisplayNamesImpl(String calendarType, int field, + int style, Locale locale) { + String key = getKey(calendarType, field, style); + Map map = new TreeMap<>(LengthBasedComparator.INSTANCE); + if (key != null) { + ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); + if (rb.containsKey(key)) { + String[] strings = rb.getStringArray(key); + if (field == YEAR) { + if (strings.length > 0) { + map.put(strings[0], 1); + } + } else { + int base = (field == DAY_OF_WEEK) ? 1 : 0; + for (int i = 0; i < strings.length; i++) { + String name = strings[i]; + // Ignore any empty string (some standalone month names + // are not defined) + if (name.length() == 0) { + continue; + } + map.put(name, base + i); + } + } + } + } + return map; + } + + /** + * Comparator implementation for TreeMap which iterates keys from longest + * to shortest. + */ + private static class LengthBasedComparator implements Comparator { + private static final LengthBasedComparator INSTANCE = new LengthBasedComparator(); + + private LengthBasedComparator() { + } + + @Override + public int compare(String o1, String o2) { + int n = o2.length() - o1.length(); + return (n == 0) ? o1.compareTo(o2) : n; + } + } + + @Override + public Locale[] getAvailableLocales() { + return LocaleProviderAdapter.toLocaleArray(langtags); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + if (Locale.ROOT.equals(locale)) { + return true; + } + String calendarType = null; + if (locale.hasExtensions()) { + calendarType = locale.getUnicodeLocaleType("ca"); + locale = locale.stripExtensions(); + } + + if (calendarType != null) { + switch (calendarType) { + case "buddhist": + case "japanese": + case "gregory": + break; + default: + // Unknown calendar type + return false; + } + } + if (langtags.contains(locale.toLanguageTag())) { + return true; + } + if (type == LocaleProviderAdapter.Type.JRE) { + String oldname = locale.toString().replace('_', '-'); + return langtags.contains(oldname); + } + return false; + } + + @Override + public Set getAvailableLanguageTags() { + return langtags; + } + + private int getIntData(String key, Locale locale) { + ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getCalendarData(locale); + if (rb.containsKey(key)) { + String firstday = rb.getString(key); + return Integer.parseInt(firstday); + } + // Note that the base bundle of CLDR doesn't have the Calendar week parameters. + return 0; + } + + private String getKey(String type, int field, int style) { + boolean standalone = (style & 0x8000) != 0; + style &= ~0x8000; + + if ("gregory".equals(type)) { + type = null; + } + + StringBuilder key = new StringBuilder(); + switch (field) { + case ERA: + if (type != null) { + key.append(type).append('.'); + } + if (style == SHORT) { + key.append("short."); + } + key.append("Eras"); + break; + + case YEAR: + key.append(type).append(".FirstYear"); + break; + + case MONTH: + if (standalone) { + key.append("standalone."); + } + key.append(style == SHORT ? "MonthAbbreviations" : "MonthNames"); + break; + + case DAY_OF_WEEK: + key.append(style == SHORT ? "DayAbbreviations" : "DayNames"); + break; + + case AM_PM: + key.append("AmPmMarkers"); + break; + } + return key.length() > 0 ? key.toString() : null; + } +}