1 /* 2 * Copyright (c) 2012, 2017, 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.Optional; 32 import java.util.spi.CalendarDataProvider; 33 import java.util.spi.CalendarNameProvider; 34 35 /** 36 * {@code CalendarDataUtility} is a utility class for calling the 37 * {@link CalendarDataProvider} methods. 38 * 39 * @author Masayoshi Okutsu 40 * @author Naoto Sato 41 */ 42 public class CalendarDataUtility { 43 public static final String FIRST_DAY_OF_WEEK = "firstDayOfWeek"; 44 public static final String MINIMAL_DAYS_IN_FIRST_WEEK = "minimalDaysInFirstWeek"; 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).orElse(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).orElse(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 */ 134 public static Optional<Locale> findRegionOverride(Locale l) { 135 String rg = l.getUnicodeLocaleType("rg"); 136 Locale override = null; 137 138 if (rg != null && rg.length() == 6) { 139 // UN M.49 code should not be allowed here 140 // cannot use regex here, as it could be a recursive call 141 rg = rg.toUpperCase(Locale.ROOT); 142 if (rg.charAt(0) >= 0x0041 && 143 rg.charAt(0) <= 0x005A && 144 rg.charAt(1) >= 0x0041 && 145 rg.charAt(1) <= 0x005A && 146 rg.substring(2).equals("ZZZZ")) { 147 override = new Locale.Builder().setLocale(l) 148 .setRegion(rg.substring(0, 2)) 149 .build(); 150 } 151 } 152 153 return Optional.ofNullable(override); 154 } 155 156 static String normalizeCalendarType(String requestID) { 157 String type; 158 if (requestID.equals("gregorian") || requestID.equals("iso8601")) { 159 type = "gregory"; 160 } else if (requestID.startsWith("islamic")) { 161 type = "islamic"; 162 } else { 163 type = requestID; 164 } 165 return type; 166 } 167 168 /** 169 * Obtains a localized field value string from a CalendarDataProvider 170 * implementation. 171 */ 172 private static class CalendarFieldValueNameGetter 173 implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarNameProvider, 174 String> { 175 private static final CalendarFieldValueNameGetter INSTANCE = 176 new CalendarFieldValueNameGetter(); 177 178 @Override 179 public String getObject(CalendarNameProvider calendarNameProvider, 180 Locale locale, 181 String requestID, // calendarType 182 Object... params) { 183 assert params.length == 4; 184 int field = (int) params[0]; 185 int value = (int) params[1]; 186 int style = (int) params[2]; 187 boolean javatime = (boolean) params[3]; 188 189 // If javatime is true, resources from CLDR have precedence over JRE 190 // native resources. 191 if (javatime && calendarNameProvider instanceof CalendarNameProviderImpl) { 192 String name; 193 name = ((CalendarNameProviderImpl)calendarNameProvider) 194 .getJavaTimeDisplayName(requestID, field, value, style, locale); 195 return name; 196 } 197 return calendarNameProvider.getDisplayName(requestID, field, value, style, locale); 198 } 199 } 200 201 /** 202 * Obtains a localized field-value pairs from a CalendarDataProvider 203 * implementation. 204 */ 205 private static class CalendarFieldValueNamesMapGetter 206 implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarNameProvider, 207 Map<String, Integer>> { 208 private static final CalendarFieldValueNamesMapGetter INSTANCE = 209 new CalendarFieldValueNamesMapGetter(); 210 211 @Override 212 public Map<String, Integer> getObject(CalendarNameProvider calendarNameProvider, 213 Locale locale, 214 String requestID, // calendarType 215 Object... params) { 216 assert params.length == 3; 217 int field = (int) params[0]; 218 int style = (int) params[1]; 219 boolean javatime = (boolean) params[2]; 220 221 // If javatime is true, resources from CLDR have precedence over JRE 222 // native resources. 223 if (javatime && calendarNameProvider instanceof CalendarNameProviderImpl) { 224 Map<String, Integer> map; 225 map = ((CalendarNameProviderImpl)calendarNameProvider) 226 .getJavaTimeDisplayNames(requestID, field, style, locale); 227 return map; 228 } 229 return calendarNameProvider.getDisplayNames(requestID, field, style, locale); 230 } 231 } 232 233 private static class CalendarWeekParameterGetter 234 implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarDataProvider, 235 Integer> { 236 private static final CalendarWeekParameterGetter INSTANCE = 237 new CalendarWeekParameterGetter(); 238 239 @Override 240 public Integer getObject(CalendarDataProvider calendarDataProvider, 241 Locale locale, 242 String requestID, // resource key 243 Object... params) { 244 assert params.length == 0; 245 int value; 246 switch (requestID) { 247 case FIRST_DAY_OF_WEEK: 248 value = calendarDataProvider.getFirstDayOfWeek(locale); 249 break; 250 case MINIMAL_DAYS_IN_FIRST_WEEK: 251 value = calendarDataProvider.getMinimalDaysInFirstWeek(locale); 252 break; 253 default: 254 throw new InternalError("invalid requestID: " + requestID); 255 } 256 return (value != 0) ? value : null; 257 } 258 } 259 }