1 /* 2 * Copyright (c) 2012, 2019, 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 26 package sun.util.locale.provider; 27 28 import static java.util.Calendar.*; 29 import java.util.Locale; 30 import java.util.Map; 31 import java.util.spi.CalendarDataProvider; 32 import java.util.spi.CalendarNameProvider; 33 34 /** 35 * {@code CalendarDataUtility} is a utility class for calling the 36 * {@link CalendarDataProvider} methods. 37 * 38 * @author Masayoshi Okutsu 39 * @author Naoto Sato 40 */ 41 public class CalendarDataUtility { 42 public static final String FIRST_DAY_OF_WEEK = "firstDayOfWeek"; 43 public static final String MINIMAL_DAYS_IN_FIRST_WEEK = "minimalDaysInFirstWeek"; 44 private static final Locale.Builder OVERRIDE_BUILDER = new Locale.Builder(); 45 46 // No instantiation 47 private CalendarDataUtility() { 48 } 49 50 public static int retrieveFirstDayOfWeek(Locale locale) { 51 // Look for the Unicode Extension in the locale parameter 52 if (locale.hasExtensions()) { 53 String fw = locale.getUnicodeLocaleType("fw"); 54 if (fw != null) { 55 switch (fw.toLowerCase(Locale.ROOT)) { 56 case "mon": 57 return MONDAY; 58 case "tue": 59 return TUESDAY; 60 case "wed": 61 return WEDNESDAY; 62 case "thu": 63 return THURSDAY; 64 case "fri": 65 return FRIDAY; 66 case "sat": 67 return SATURDAY; 68 case "sun": 69 return SUNDAY; 70 } 71 } 72 } 73 74 LocaleServiceProviderPool pool = 75 LocaleServiceProviderPool.getPool(CalendarDataProvider.class); 76 Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE, 77 findRegionOverride(locale), 78 true, FIRST_DAY_OF_WEEK); 79 return (value != null && (value >= SUNDAY && value <= SATURDAY)) ? value : SUNDAY; 80 } 81 82 public static int retrieveMinimalDaysInFirstWeek(Locale locale) { 83 LocaleServiceProviderPool pool = 84 LocaleServiceProviderPool.getPool(CalendarDataProvider.class); 85 Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE, 86 findRegionOverride(locale), 87 true, MINIMAL_DAYS_IN_FIRST_WEEK); 88 return (value != null && (value >= 1 && value <= 7)) ? value : 1; 89 } 90 91 public static String retrieveFieldValueName(String id, int field, int value, int style, Locale locale) { 92 LocaleServiceProviderPool pool = 93 LocaleServiceProviderPool.getPool(CalendarNameProvider.class); 94 return pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), 95 field, value, style, false); 96 } 97 98 public static String retrieveJavaTimeFieldValueName(String id, int field, int value, int style, Locale locale) { 99 LocaleServiceProviderPool pool = 100 LocaleServiceProviderPool.getPool(CalendarNameProvider.class); 101 String name; 102 name = pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), 103 field, value, style, true); 104 if (name == null) { 105 name = pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), 106 field, value, style, false); 107 } 108 return name; 109 } 110 111 public static Map<String, Integer> retrieveFieldValueNames(String id, int field, int style, Locale locale) { 112 LocaleServiceProviderPool pool = 113 LocaleServiceProviderPool.getPool(CalendarNameProvider.class); 114 return pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, 115 normalizeCalendarType(id), field, style, false); 116 } 117 118 public static Map<String, Integer> retrieveJavaTimeFieldValueNames(String id, int field, int style, Locale locale) { 119 LocaleServiceProviderPool pool = 120 LocaleServiceProviderPool.getPool(CalendarNameProvider.class); 121 Map<String, Integer> map; 122 map = pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, 123 normalizeCalendarType(id), field, style, true); 124 if (map == null) { 125 map = pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, 126 normalizeCalendarType(id), field, style, false); 127 } 128 return map; 129 } 130 131 /** 132 * Utility to look for a region override extension. 133 * If no region override is found, returns the original locale. 134 */ 135 public static Locale findRegionOverride(Locale l) { 136 String rg = l.getUnicodeLocaleType("rg"); 137 Locale override = l; 138 139 if (rg != null && rg.length() == 6) { 140 // UN M.49 code should not be allowed here 141 // cannot use regex here, as it could be a recursive call 142 rg = rg.toUpperCase(Locale.ROOT); 143 if (rg.charAt(0) >= 0x0041 && 144 rg.charAt(0) <= 0x005A && 145 rg.charAt(1) >= 0x0041 && 146 rg.charAt(1) <= 0x005A && 147 rg.substring(2).equals("ZZZZ")) { 148 override = OVERRIDE_BUILDER 149 .clear() 150 .setLocale(l) 151 .setRegion(rg.substring(0, 2)) 152 .build(); 153 } 154 } 155 156 return override; 157 } 158 159 static String normalizeCalendarType(String requestID) { 160 String type; 161 if (requestID.equals("gregorian") || requestID.equals("iso8601")) { 162 type = "gregory"; 163 } else if (requestID.startsWith("islamic")) { 164 type = "islamic"; 165 } else { 166 type = requestID; 167 } 168 return type; 169 } 170 171 /** 172 * Obtains a localized field value string from a CalendarDataProvider 173 * implementation. 174 */ 175 private static class CalendarFieldValueNameGetter 176 implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarNameProvider, 177 String> { 178 private static final CalendarFieldValueNameGetter INSTANCE = 179 new CalendarFieldValueNameGetter(); 180 181 @Override 182 public String getObject(CalendarNameProvider calendarNameProvider, 183 Locale locale, 184 String requestID, // calendarType 185 Object... params) { 186 assert params.length == 4; 187 int field = (int) params[0]; 188 int value = (int) params[1]; 189 int style = (int) params[2]; 190 boolean javatime = (boolean) params[3]; 191 192 // If javatime is true, resources from CLDR have precedence over JRE 193 // native resources. 194 if (javatime && calendarNameProvider instanceof CalendarNameProviderImpl) { 195 String name; 196 name = ((CalendarNameProviderImpl)calendarNameProvider) 197 .getJavaTimeDisplayName(requestID, field, value, style, locale); 198 return name; 199 } 200 return calendarNameProvider.getDisplayName(requestID, field, value, style, locale); 201 } 202 } 203 204 /** 205 * Obtains a localized field-value pairs from a CalendarDataProvider 206 * implementation. 207 */ 208 private static class CalendarFieldValueNamesMapGetter 209 implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarNameProvider, 210 Map<String, Integer>> { 211 private static final CalendarFieldValueNamesMapGetter INSTANCE = 212 new CalendarFieldValueNamesMapGetter(); 213 214 @Override 215 public Map<String, Integer> getObject(CalendarNameProvider calendarNameProvider, 216 Locale locale, 217 String requestID, // calendarType 218 Object... params) { 219 assert params.length == 3; 220 int field = (int) params[0]; 221 int style = (int) params[1]; 222 boolean javatime = (boolean) params[2]; 223 224 // If javatime is true, resources from CLDR have precedence over JRE 225 // native resources. 226 if (javatime && calendarNameProvider instanceof CalendarNameProviderImpl) { 227 Map<String, Integer> map; 228 map = ((CalendarNameProviderImpl)calendarNameProvider) 229 .getJavaTimeDisplayNames(requestID, field, style, locale); 230 return map; 231 } 232 return calendarNameProvider.getDisplayNames(requestID, field, style, locale); 233 } 234 } 235 236 private static class CalendarWeekParameterGetter 237 implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarDataProvider, 238 Integer> { 239 private static final CalendarWeekParameterGetter INSTANCE = 240 new CalendarWeekParameterGetter(); 241 242 @Override 243 public Integer getObject(CalendarDataProvider calendarDataProvider, 244 Locale locale, 245 String requestID, // resource key 246 Object... params) { 247 assert params.length == 0; 248 int value; 249 switch (requestID) { 250 case FIRST_DAY_OF_WEEK: 251 value = calendarDataProvider.getFirstDayOfWeek(locale); 252 if (value == 0) { 253 value = MONDAY; // default for the world ("001") 254 } 255 break; 256 case MINIMAL_DAYS_IN_FIRST_WEEK: 257 value = calendarDataProvider.getMinimalDaysInFirstWeek(locale); 258 if (value == 0) { 259 value = 1; // default for the world ("001") 260 } 261 break; 262 default: 263 throw new InternalError("invalid requestID: " + requestID); 264 } 265 266 assert value != 0; 267 return value; 268 } 269 } 270 }