1 /* 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 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 package sun.util.locale.provider; 26 27 import static java.util.Calendar.*; 28 import java.util.HashMap; 29 import java.util.Locale; 30 import java.util.Map; 31 import java.util.ResourceBundle; 32 import java.util.Set; 33 import java.util.spi.CalendarDataProvider; 34 35 /** 36 * Concrete implementation of the {@link java.util.spi.CalendarDataProvider 37 * CalendarDataProvider} class for the JRE LocaleProviderAdapter. 38 * 39 * @author Masayoshi Okutsu 40 * @author Naoto Sato 41 */ 42 public class CalendarDataProviderImpl extends CalendarDataProvider implements AvailableLanguageTags { 43 private final LocaleProviderAdapter.Type type; 44 private final Set<String> langtags; 45 46 public CalendarDataProviderImpl(LocaleProviderAdapter.Type type, Set<String> langtags) { 47 this.type = type; 48 this.langtags = langtags; 49 } 50 51 @Override 52 public int getFirstDayOfWeek(Locale locale) { 53 return getIntData(CalendarDataUtility.FIRST_DAY_OF_WEEK, locale); 54 } 55 56 @Override 57 public int getMinimalDaysInFirstWeek(Locale locale) { 58 return getIntData(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK, locale); 59 } 60 61 @Override 62 public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) { 63 String name = null; 64 String key = getKey(calendarType, field, style); 65 if (key != null) { 66 ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); 67 if (rb.containsKey(key)) { 68 String[] strings = rb.getStringArray(key); 69 if (strings.length > 0) { 70 if (field == DAY_OF_WEEK || field == YEAR) { 71 --value; 72 } 73 name = strings[value]; 74 // If name is empty in standalone, try its `format' style. 75 if (name.length() == 0 76 && (style == SHORT_STANDALONE || style == LONG_STANDALONE)) { 77 name = getDisplayName(calendarType, field, value, 78 style == SHORT_STANDALONE ? SHORT_FORMAT : LONG_FORMAT, 79 locale); 80 } 81 } 82 } 83 } 84 return name; 85 } 86 87 @Override 88 public Map<String, Integer> getDisplayNames(String calendarType, int field, int style, Locale locale) { 89 Map<String, Integer> names; 90 if (style == ALL_STYLES) { 91 names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale); 92 if (field != AM_PM) { 93 for (int st : new int[] { SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE }) { 94 names.putAll(getDisplayNamesImpl(calendarType, field, st, locale)); 95 } 96 } 97 } else { 98 // specific style 99 names = getDisplayNamesImpl(calendarType, field, style, locale); 100 } 101 return names.isEmpty() ? null : names; 102 } 103 104 private Map<String, Integer> getDisplayNamesImpl(String calendarType, int field, 105 int style, Locale locale) { 106 String key = getKey(calendarType, field, style); 107 Map<String, Integer> map = new HashMap<>(); 108 if (key != null) { 109 ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); 110 if (rb.containsKey(key)) { 111 String[] strings = rb.getStringArray(key); 112 if (field == YEAR) { 113 if (strings.length > 0) { 114 map.put(strings[0], 1); 115 } 116 } else { 117 int base = (field == DAY_OF_WEEK) ? 1 : 0; 118 for (int i = 0; i < strings.length; i++) { 119 String name = strings[i]; 120 // Ignore any empty string (some standalone month names 121 // are not defined) 122 if (name.length() == 0) { 123 continue; 124 } 125 map.put(name, base + i); 126 } 127 } 128 } 129 } 130 return map; 131 } 132 133 @Override 134 public Locale[] getAvailableLocales() { 135 return LocaleProviderAdapter.toLocaleArray(langtags); 136 } 137 138 @Override 139 public boolean isSupportedLocale(Locale locale) { 140 if (Locale.ROOT.equals(locale)) { 141 return true; 142 } 143 String calendarType = null; 144 if (locale.hasExtensions()) { 145 calendarType = locale.getUnicodeLocaleType("ca"); 146 locale = locale.stripExtensions(); 147 } 148 149 if (calendarType != null) { 150 switch (calendarType) { 151 case "buddhist": 152 case "japanese": 153 case "gregory": 154 break; 155 default: 156 // Unknown calendar type 157 return false; 158 } 159 } 160 if (langtags.contains(locale.toLanguageTag())) { 161 return true; 162 } 163 if (type == LocaleProviderAdapter.Type.JRE) { 164 String oldname = locale.toString().replace('_', '-'); 165 return langtags.contains(oldname); 166 } 167 return false; 168 } 169 170 @Override 171 public Set<String> getAvailableLanguageTags() { 172 return langtags; 173 } 174 175 private int getIntData(String key, Locale locale) { 176 ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getCalendarData(locale); 177 if (rb.containsKey(key)) { 178 String firstday = rb.getString(key); 179 return Integer.parseInt(firstday); 180 } 181 // Note that the base bundle of CLDR doesn't have the Calendar week parameters. 182 return 0; 183 } 184 185 private String getKey(String type, int field, int style) { 186 boolean standalone = (style & 0x8000) != 0; 187 style &= ~0x8000; 188 189 if ("gregory".equals(type)) { 190 type = null; 191 } 192 193 StringBuilder key = new StringBuilder(); 194 switch (field) { 195 case ERA: 196 if (type != null) { 197 key.append(type).append('.'); 198 } 199 if (style == SHORT) { 200 key.append("short."); 201 } 202 key.append("Eras"); 203 break; 204 205 case YEAR: 206 key.append(type).append(".FirstYear"); 207 break; 208 209 case MONTH: 210 if (standalone) { 211 key.append("standalone."); 212 } 213 key.append(style == SHORT ? "MonthAbbreviations" : "MonthNames"); 214 break; 215 216 case DAY_OF_WEEK: 217 key.append(style == SHORT ? "DayAbbreviations" : "DayNames"); 218 break; 219 220 case AM_PM: 221 key.append("AmPmMarkers"); 222 break; 223 } 224 return key.length() > 0 ? key.toString() : null; 225 } 226 }