1 /* 2 * Copyright (c) 2012, 2020, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 import java.text.*; 24 import java.text.spi.*; 25 import java.util.*; 26 import java.util.logging.Level; 27 import java.util.logging.LogManager; 28 import java.util.logging.LogRecord; 29 import java.util.logging.StreamHandler; 30 import java.util.spi.*; 31 import java.util.stream.IntStream; 32 import sun.util.locale.provider.LocaleProviderAdapter; 33 34 import static java.util.logging.LogManager.*; 35 36 public class LocaleProviders { 37 38 private static final boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows"); 39 private static final boolean IS_MAC = System.getProperty("os.name").startsWith("Mac"); 40 41 public static void main(String[] args) { 42 String methodName = args[0]; 43 44 switch (methodName) { 45 case "getPlatformLocale": 46 if (args[1].equals("format")) { 47 getPlatformLocale(Locale.Category.FORMAT); 48 } else { 49 getPlatformLocale(Locale.Category.DISPLAY); 50 } 51 break; 52 53 case "adapterTest": 54 adapterTest(args[1], args[2], (args.length >= 4 ? args[3] : "")); 55 break; 56 57 case "bug7198834Test": 58 bug7198834Test(); 59 break; 60 61 case "tzNameTest": 62 tzNameTest(args[1]); 63 break; 64 65 case "bug8001440Test": 66 bug8001440Test(); 67 break; 68 69 case "bug8010666Test": 70 bug8010666Test(); 71 break; 72 73 case "bug8013086Test": 74 bug8013086Test(args[1], args[2]); 75 break; 76 77 case "bug8013903Test": 78 bug8013903Test(); 79 break; 80 81 case "bug8027289Test": 82 bug8027289Test(args[1]); 83 break; 84 85 case "bug8220227Test": 86 bug8220227Test(); 87 break; 88 89 case "bug8228465Test": 90 bug8228465Test(); 91 break; 92 93 case "bug8232871Test": 94 bug8232871Test(); 95 break; 96 97 case "bug8232860Test": 98 bug8232860Test(); 99 break; 100 101 case "bug8245241Test": 102 bug8245241Test(args[1]); 103 break; 104 105 default: 106 throw new RuntimeException("Test method '"+methodName+"' not found."); 107 } 108 } 109 110 static void getPlatformLocale(Locale.Category cat) { 111 Locale defloc = Locale.getDefault(cat); 112 System.out.printf("%s,%s\n", defloc.getLanguage(), defloc.getCountry()); 113 } 114 115 static void adapterTest(String expected, String lang, String ctry) { 116 Locale testLocale = new Locale(lang, ctry); 117 LocaleProviderAdapter ldaExpected = 118 LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.valueOf(expected)); 119 if (!ldaExpected.getDateFormatProvider().isSupportedLocale(testLocale)) { 120 System.out.println("test locale: "+testLocale+" is not supported by the expected provider: "+ldaExpected+". Ignoring the test."); 121 return; 122 } 123 String preference = System.getProperty("java.locale.providers", ""); 124 LocaleProviderAdapter lda = LocaleProviderAdapter.getAdapter(DateFormatProvider.class, testLocale); 125 LocaleProviderAdapter.Type type = lda.getAdapterType(); 126 System.out.printf("testLocale: %s, got: %s, expected: %s\n", testLocale, type, expected); 127 if (!type.toString().equals(expected)) { 128 throw new RuntimeException("Returned locale data adapter is not correct."); 129 } 130 } 131 132 static void bug7198834Test() { 133 LocaleProviderAdapter lda = LocaleProviderAdapter.getAdapter(DateFormatProvider.class, Locale.US); 134 LocaleProviderAdapter.Type type = lda.getAdapterType(); 135 if (type == LocaleProviderAdapter.Type.HOST && IS_WINDOWS) { 136 DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, Locale.US); 137 String date = df.format(new Date()); 138 if (date.charAt(date.length()-1) == ' ') { 139 throw new RuntimeException("Windows Host Locale Provider returns a trailing space."); 140 } 141 } else { 142 System.out.println("Windows HOST locale adapter not found. Ignoring this test."); 143 } 144 } 145 146 static void tzNameTest(String id) { 147 TimeZone tz = TimeZone.getTimeZone(id); 148 String tzName = tz.getDisplayName(false, TimeZone.SHORT, Locale.US); 149 if (tzName.startsWith("GMT")) { 150 throw new RuntimeException("JRE's localized time zone name for "+id+" could not be retrieved. Returned name was: "+tzName); 151 } 152 } 153 154 static void bug8001440Test() { 155 Locale locale = Locale.forLanguageTag("th-TH-u-nu-hoge"); 156 NumberFormat nf = NumberFormat.getInstance(locale); 157 String nu = nf.format(1234560); 158 } 159 160 // This test assumes Windows localized language/country display names. 161 static void bug8010666Test() { 162 if (IS_WINDOWS) { 163 NumberFormat nf = NumberFormat.getInstance(Locale.US); 164 try { 165 double ver = nf.parse(System.getProperty("os.version")) 166 .doubleValue(); 167 System.out.printf("Windows version: %.1f\n", ver); 168 if (ver >= 6.0) { 169 LocaleProviderAdapter lda = 170 LocaleProviderAdapter.getAdapter( 171 LocaleNameProvider.class, Locale.ENGLISH); 172 LocaleProviderAdapter.Type type = lda.getAdapterType(); 173 if (type == LocaleProviderAdapter.Type.HOST) { 174 LocaleNameProvider lnp = lda.getLocaleNameProvider(); 175 Locale mkmk = Locale.forLanguageTag("mk-MK"); 176 String result = mkmk.getDisplayLanguage(Locale.ENGLISH); 177 String hostResult = 178 lnp.getDisplayLanguage(mkmk.getLanguage(), 179 Locale.ENGLISH); 180 System.out.printf(" Display language name for" + 181 " (mk_MK): result(HOST): \"%s\", returned: \"%s\"\n", 182 hostResult, result); 183 if (result == null || 184 hostResult != null && 185 !result.equals(hostResult)) { 186 throw new RuntimeException("Display language name" + 187 " mismatch for \"mk\". Returned name was" + 188 " \"" + result + "\", result(HOST): \"" + 189 hostResult + "\""); 190 } 191 result = Locale.US.getDisplayLanguage(Locale.ENGLISH); 192 hostResult = 193 lnp.getDisplayLanguage(Locale.US.getLanguage(), 194 Locale.ENGLISH); 195 System.out.printf(" Display language name for" + 196 " (en_US): result(HOST): \"%s\", returned: \"%s\"\n", 197 hostResult, result); 198 if (result == null || 199 hostResult != null && 200 !result.equals(hostResult)) { 201 throw new RuntimeException("Display language name" + 202 " mismatch for \"en\". Returned name was" + 203 " \"" + result + "\", result(HOST): \"" + 204 hostResult + "\""); 205 } 206 if (ver >= 6.1) { 207 result = Locale.US.getDisplayCountry(Locale.ENGLISH); 208 hostResult = lnp.getDisplayCountry( 209 Locale.US.getCountry(), Locale.ENGLISH); 210 System.out.printf(" Display country name for" + 211 " (en_US): result(HOST): \"%s\", returned: \"%s\"\n", 212 hostResult, result); 213 if (result == null || 214 hostResult != null && 215 !result.equals(hostResult)) { 216 throw new RuntimeException("Display country name" + 217 " mismatch for \"US\". Returned name was" + 218 " \"" + result + "\", result(HOST): \"" + 219 hostResult + "\""); 220 } 221 } 222 } else { 223 throw new RuntimeException("Windows Host" + 224 " LocaleProviderAdapter was not selected for" + 225 " English locale."); 226 } 227 } 228 } catch (ParseException pe) { 229 throw new RuntimeException("Parsing Windows version failed: "+pe.toString()); 230 } 231 } 232 } 233 234 static void bug8013086Test(String lang, String ctry) { 235 try { 236 // Throws a NullPointerException if the test fails. 237 System.out.println(new SimpleDateFormat("z", new Locale(lang, ctry)).parse("UTC")); 238 } catch (ParseException pe) { 239 // ParseException is fine in this test, as it's not "UTC" 240 } 241 } 242 243 static void bug8013903Test() { 244 if (IS_WINDOWS) { 245 Date sampleDate = new Date(0x10000000000L); 246 String hostResult = "\u5e73\u6210 16.11.03 (Wed) AM 11:53:47"; 247 String jreResult = "\u5e73\u6210 16.11.03 (\u6c34) \u5348\u524d 11:53:47"; 248 Locale l = new Locale("ja", "JP", "JP"); 249 SimpleDateFormat sdf = new SimpleDateFormat("GGGG yyyy.MMM.dd '('E')' a hh:mm:ss", l); 250 sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); 251 String result = sdf.format(sampleDate); 252 System.out.println(result); 253 if (LocaleProviderAdapter.getAdapterPreference() 254 .contains(LocaleProviderAdapter.Type.JRE)) { 255 if (!jreResult.equals(result)) { 256 throw new RuntimeException("Format failed. result: \"" + 257 result + "\", expected: \"" + jreResult); 258 } 259 } else { 260 // Windows display names. Subject to change if Windows changes its format. 261 if (!hostResult.equals(result)) { 262 throw new RuntimeException("Format failed. result: \"" + 263 result + "\", expected: \"" + hostResult); 264 } 265 } 266 } 267 } 268 269 static void bug8027289Test(String expectedCodePoint) { 270 if (IS_WINDOWS) { 271 char[] expectedSymbol = Character.toChars(Integer.valueOf(expectedCodePoint, 16)); 272 NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.CHINA); 273 char formatted = nf.format(7000).charAt(0); 274 System.out.println("returned: " + formatted + ", expected: " + expectedSymbol[0]); 275 if (formatted != expectedSymbol[0]) { 276 throw new RuntimeException( 277 "Unexpected Chinese currency symbol. returned: " 278 + formatted + ", expected: " + expectedSymbol[0]); 279 } 280 } 281 } 282 283 static void bug8220227Test() { 284 if (IS_WINDOWS) { 285 Locale l = new Locale("xx","XX"); 286 String country = l.getDisplayCountry(); 287 if (country.endsWith("(XX)")) { 288 throw new RuntimeException( 289 "Unexpected Region name: " + country); 290 } 291 } 292 } 293 294 static void bug8228465Test() { 295 LocaleProviderAdapter lda = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, Locale.US); 296 LocaleProviderAdapter.Type type = lda.getAdapterType(); 297 if (type == LocaleProviderAdapter.Type.HOST && IS_WINDOWS) { 298 var names = new GregorianCalendar() 299 .getDisplayNames(Calendar.ERA, Calendar.SHORT_FORMAT, Locale.US); 300 if (!names.keySet().contains("AD") || 301 names.get("AD").intValue() != 1) { 302 throw new RuntimeException( 303 "Short Era name for 'AD' is missing or incorrect"); 304 } else { 305 System.out.println("bug8228465Test succeeded."); 306 } 307 } 308 } 309 310 static void bug8232871Test() { 311 LocaleProviderAdapter lda = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, Locale.US); 312 LocaleProviderAdapter.Type type = lda.getAdapterType(); 313 var lang = Locale.getDefault().getLanguage(); 314 var cal = Calendar.getInstance(); 315 var calType = cal.getCalendarType(); 316 var expected = "\u4ee4\u548c1\u5e745\u67081\u65e5 \u6c34\u66dc\u65e5 \u5348\u524d0:00:00 \u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u590f\u6642\u9593"; 317 318 if (type == LocaleProviderAdapter.Type.HOST && 319 IS_MAC && 320 lang.equals("ja") && 321 calType.equals("japanese")) { 322 cal.set(1, 4, 1, 0, 0, 0); 323 cal.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); 324 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, 325 Locale.JAPAN); 326 df.setCalendar(cal); 327 var result = df.format(cal.getTime()); 328 if (result.equals(expected)) { 329 System.out.println("bug8232871Test succeeded."); 330 } else { 331 throw new RuntimeException( 332 "Japanese calendar names mismatch. result: " + 333 result + 334 ", expected: " + 335 expected); 336 } 337 } else { 338 System.out.println("Test ignored. Either :-\n" + 339 "OS is not macOS, or\n" + 340 "provider is not HOST: " + type + ", or\n" + 341 "Language is not Japanese: " + lang + ", or\n" + 342 "native calendar is not JapaneseCalendar: " + calType); 343 } 344 } 345 346 static void bug8232860Test() { 347 var inputList = List.of(123, 123.4); 348 var nfExpectedList = List.of("123", "123.4"); 349 var ifExpectedList = List.of("123", "123"); 350 351 var defLoc = Locale.getDefault(Locale.Category.FORMAT); 352 var type = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, Locale.US) 353 .getAdapterType(); 354 if (defLoc.equals(Locale.US) && 355 type == LocaleProviderAdapter.Type.HOST && 356 (IS_WINDOWS || IS_MAC)) { 357 final var numf = NumberFormat.getNumberInstance(Locale.US); 358 final var intf = NumberFormat.getIntegerInstance(Locale.US); 359 360 IntStream.range(0, inputList.size()) 361 .forEach(i -> { 362 var input = inputList.get(i); 363 var nfExpected = nfExpectedList.get(i); 364 var result = numf.format(input); 365 if (!result.equals(nfExpected)) { 366 throw new RuntimeException("Incorrect number format. " + 367 "input: " + input + ", expected: " + 368 nfExpected + ", result: " + result); 369 } 370 371 var ifExpected = ifExpectedList.get(i); 372 result = intf.format(input); 373 if (!result.equals(ifExpected)) { 374 throw new RuntimeException("Incorrect integer format. " + 375 "input: " + input + ", expected: " + 376 ifExpected + ", result: " + result); 377 } 378 }); 379 System.out.println("bug8232860Test succeeded."); 380 } else { 381 System.out.println("Test ignored. Either :-\n" + 382 "Default format locale is not Locale.US: " + defLoc + ", or\n" + 383 "OS is neither macOS/Windows, or\n" + 384 "provider is not HOST: " + type); 385 } 386 } 387 388 static void bug8245241Test(String expected) { 389 LogRecord[] lra = new LogRecord[1]; 390 StreamHandler handler = new StreamHandler() { 391 @Override 392 public void publish(LogRecord record) { 393 lra[0] = record; 394 } 395 }; 396 getLogManager().getLogger("").addHandler(handler); 397 398 DateFormat.getDateInstance(); // this will init LocaleProviderAdapter 399 handler.flush(); 400 401 if (lra[0] == null || 402 lra[0].getLevel() != Level.INFO || 403 !lra[0].getMessage().equals(expected)) { 404 throw new RuntimeException("Expected log was not emitted. LogRecord: " + lra[0]); 405 } 406 } 407 }