8010666: Implement Currency/LocaleNameProvider in Windows Host LocaleProviderAdapter
Reviewed-by: okutsu
--- a/jdk/src/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java Wed Apr 17 11:34:31 2013 +0200
+++ b/jdk/src/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java Mon Apr 22 13:37:07 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -520,14 +520,22 @@
}
private static boolean isSupportedCalendarLocale(Locale locale) {
- Locale base = locale.stripExtensions();
+ Locale base = locale;
+
+ if (base.hasExtensions() || base.getVariant() != "") {
+ base = new Locale.Builder()
+ .setLocale(locale)
+ .clearExtensions()
+ .build();
+ }
+
if (!supportedLocaleSet.contains(base)) {
return false;
}
String requestedCalType = locale.getUnicodeLocaleType("ca");
String nativeCalType =
- getCalendarID(locale.toLanguageTag()).replaceFirst("gregorian", "gregory");
+ getCalendarID(base.toLanguageTag()).replaceFirst("gregorian", "gregory");
if (requestedCalType == null) {
return Calendar.getAvailableCalendarTypes().contains(nativeCalType);
--- a/jdk/src/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java Wed Apr 17 11:34:31 2013 +0200
+++ b/jdk/src/windows/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java Mon Apr 22 13:37:07 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -37,6 +37,7 @@
import java.text.spi.NumberFormatProvider;
import java.util.Calendar;
import java.util.Collections;
+import java.util.Currency;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
@@ -48,6 +49,8 @@
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.spi.CalendarDataProvider;
import java.util.spi.CalendarNameProvider;
+import java.util.spi.CurrencyNameProvider;
+import java.util.spi.LocaleNameProvider;
import sun.util.spi.CalendarProvider;
/**
@@ -72,6 +75,14 @@
private static final int CD_FIRSTDAYOFWEEK = 0;
private static final int CD_MINIMALDAYSINFIRSTWEEK = 1;
+ // Currency/Locale display name types
+ private static final int DN_CURRENCY_NAME = 0;
+ private static final int DN_CURRENCY_SYMBOL = 1;
+ private static final int DN_LOCALE_LANGUAGE = 2;
+ private static final int DN_LOCALE_SCRIPT = 3;
+ private static final int DN_LOCALE_REGION = 4;
+ private static final int DN_LOCALE_VARIANT = 5;
+
// Native Calendar ID to LDML calendar type map
private static final String[] calIDToLDML = {
"",
@@ -96,15 +107,25 @@
private static ConcurrentMap<Locale, SoftReference<DecimalFormatSymbols>> decimalFormatSymbolsCache = new ConcurrentHashMap<>();
private static final Set<Locale> supportedLocaleSet;
+ private static final String nativeDisplayLanguage;
static {
Set<Locale> tmpSet = new HashSet<>();
if (initialize()) {
// Assuming the default locales do not include any extensions, so
// no stripping is needed here.
- Locale l = Locale.forLanguageTag(getDefaultLocale(CAT_FORMAT).replace('_', '-'));
- tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l));
- l = Locale.forLanguageTag(getDefaultLocale(CAT_DISPLAY).replace('_', '-'));
- tmpSet.addAll(Control.getNoFallbackControl(Control.FORMAT_DEFAULT).getCandidateLocales("", l));
+ Control c = Control.getNoFallbackControl(Control.FORMAT_DEFAULT);
+ String displayLocale = getDefaultLocale(CAT_DISPLAY);
+ Locale l = Locale.forLanguageTag(displayLocale.replace('_', '-'));
+ tmpSet.addAll(c.getCandidateLocales("", l));
+ nativeDisplayLanguage = l.getLanguage();
+
+ String formatLocale = getDefaultLocale(CAT_FORMAT);
+ if (!formatLocale.equals(displayLocale)) {
+ l = Locale.forLanguageTag(formatLocale.replace('_', '-'));
+ tmpSet.addAll(c.getCandidateLocales("", l));
+ }
+ } else {
+ nativeDisplayLanguage = "";
}
supportedLocaleSet = Collections.unmodifiableSet(tmpSet);
}
@@ -392,6 +413,96 @@
};
}
+ public static CurrencyNameProvider getCurrencyNameProvider() {
+ return new CurrencyNameProvider() {
+ @Override
+ public Locale[] getAvailableLocales() {
+ return supportedLocale;
+ }
+
+ @Override
+ public boolean isSupportedLocale(Locale locale) {
+ // Ignore the extensions for now
+ return supportedLocaleSet.contains(locale.stripExtensions()) &&
+ locale.getLanguage().equals(nativeDisplayLanguage);
+ }
+
+ @Override
+ public String getSymbol(String currencyCode, Locale locale) {
+ // Retrieves the currency symbol by calling
+ // GetLocaleInfoEx(LOCALE_SCURRENCY).
+ // It only works with the "locale"'s currency in its native
+ // language.
+ try {
+ if (Currency.getInstance(locale).getCurrencyCode()
+ .equals(currencyCode)) {
+ return getDisplayString(locale.toLanguageTag(),
+ DN_CURRENCY_SYMBOL, currencyCode);
+ }
+ } catch (IllegalArgumentException iae) {}
+ return null;
+ }
+
+ @Override
+ public String getDisplayName(String currencyCode, Locale locale) {
+ // Retrieves the display name by calling
+ // GetLocaleInfoEx(LOCALE_SNATIVECURRNAME).
+ // It only works with the "locale"'s currency in its native
+ // language.
+ try {
+ if (Currency.getInstance(locale).getCurrencyCode()
+ .equals(currencyCode)) {
+ return getDisplayString(locale.toLanguageTag(),
+ DN_CURRENCY_NAME, currencyCode);
+ }
+ } catch (IllegalArgumentException iae) {}
+ return null;
+ }
+ };
+ }
+
+ public static LocaleNameProvider getLocaleNameProvider() {
+ return new LocaleNameProvider() {
+ @Override
+ public Locale[] getAvailableLocales() {
+ return supportedLocale;
+ }
+
+ @Override
+ public boolean isSupportedLocale(Locale locale) {
+ return supportedLocaleSet.contains(locale.stripExtensions()) &&
+ locale.getLanguage().equals(nativeDisplayLanguage);
+ }
+
+ @Override
+ public String getDisplayLanguage(String languageCode, Locale locale) {
+ // Retrieves the display language name by calling
+ // GetLocaleInfoEx(LOCALE_SLOCALIZEDLANGUAGENAME).
+ return getDisplayString(locale.toLanguageTag(),
+ DN_LOCALE_LANGUAGE, languageCode);
+ }
+
+ @Override
+ public String getDisplayCountry(String countryCode, Locale locale) {
+ // Retrieves the display country name by calling
+ // GetLocaleInfoEx(LOCALE_SLOCALIZEDCOUNTRYNAME).
+ return getDisplayString(locale.toLanguageTag(),
+ DN_LOCALE_REGION, nativeDisplayLanguage+"-"+countryCode);
+ }
+
+ @Override
+ public String getDisplayScript(String scriptCode, Locale locale) {
+ return null;
+ }
+
+ @Override
+ public String getDisplayVariant(String variantCode, Locale locale) {
+ return null;
+ }
+ };
+ }
+
+
private static String convertDateTimePattern(String winPattern) {
String ret = winPattern.replaceAll("dddd", "EEEE");
ret = ret.replaceAll("ddd", "EEE");
@@ -413,12 +524,21 @@
}
private static boolean isSupportedCalendarLocale(Locale locale) {
- Locale base = locale.stripExtensions();
+ Locale base = locale;
+
+ if (base.hasExtensions() || base.getVariant() != "") {
+ // strip off extensions and variant.
+ base = new Locale.Builder()
+ .setLocale(locale)
+ .clearExtensions()
+ .build();
+ }
+
if (!supportedLocaleSet.contains(base)) {
return false;
}
- int calid = getCalendarID(locale.toLanguageTag());
+ int calid = getCalendarID(base.toLanguageTag());
if (calid <= 0 || calid >= calIDToLDML.length) {
return false;
}
@@ -546,4 +666,7 @@
// For CalendarDataProvider
private static native int getCalendarDataValue(String langTag, int type);
+
+ // For Locale/CurrencyNameProvider
+ private static native String getDisplayString(String langTag, int key, String value);
}
--- a/jdk/src/windows/native/sun/util/locale/provider/HostLocaleProviderAdapter_md.c Wed Apr 17 11:34:31 2013 +0200
+++ b/jdk/src/windows/native/sun/util/locale/provider/HostLocaleProviderAdapter_md.c Mon Apr 22 13:37:07 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -196,7 +196,7 @@
break;
}
- localeString = getJavaIDFromLangID(langid);
+ localeString = (char *)getJavaIDFromLangID(langid);
ret = (*env)->NewStringUTF(env, localeString);
free(localeString);
return ret;
@@ -366,12 +366,14 @@
*/
JNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_isNativeDigit
(JNIEnv *env, jclass cls, jstring jlangtag) {
- WCHAR buf[BUFLEN];
+ DWORD num;
const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
- int got = getLocaleInfoWrapper(langtag, LOCALE_IDIGITSUBSTITUTION, buf, BUFLEN);
+ int got = getLocaleInfoWrapper(langtag,
+ LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&num, sizeof(num));
(*env)->ReleaseStringChars(env, jlangtag, langtag);
- return got && buf[0] == L'2'; // 2: native digit substitution
+ return got && num == 2; // 2: native digit substitution
}
/*
@@ -590,25 +592,72 @@
*/
JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDataValue
(JNIEnv *env, jclass cls, jstring jlangtag, jint type) {
- WCHAR buf[BUFLEN];
+ DWORD num;
const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE);
int got = 0;
switch (type) {
case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK:
- got = getLocaleInfoWrapper(langtag, LOCALE_IFIRSTDAYOFWEEK, buf, BUFLEN);
+ got = getLocaleInfoWrapper(langtag,
+ LOCALE_IFIRSTDAYOFWEEK | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&num, sizeof(num));
break;
}
(*env)->ReleaseStringChars(env, jlangtag, langtag);
if (got) {
- return _wtoi(buf);
+ return num;
} else {
return -1;
}
}
+/*
+ * Class: sun_util_locale_provider_HostLocaleProviderAdapterImpl
+ * Method: getDisplayString
+ * Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDisplayString
+ (JNIEnv *env, jclass cls, jstring jlangtag, jint type, jstring jvalue) {
+ LCTYPE lcType;
+ jstring jStr;
+ const jchar * pjChar;
+ WCHAR buf[BUFLEN];
+ int got = 0;
+
+ switch (type) {
+ case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_NAME:
+ lcType = LOCALE_SNATIVECURRNAME;
+ jStr = jlangtag;
+ break;
+ case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_CURRENCY_SYMBOL:
+ lcType = LOCALE_SCURRENCY;
+ jStr = jlangtag;
+ break;
+ case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_LANGUAGE:
+ lcType = LOCALE_SLOCALIZEDLANGUAGENAME;
+ jStr = jvalue;
+ break;
+ case sun_util_locale_provider_HostLocaleProviderAdapterImpl_DN_LOCALE_REGION:
+ lcType = LOCALE_SLOCALIZEDCOUNTRYNAME;
+ jStr = jvalue;
+ break;
+ default:
+ return NULL;
+ }
+
+ pjChar = (*env)->GetStringChars(env, jStr, JNI_FALSE);
+ got = getLocaleInfoWrapper(pjChar, lcType, buf, BUFLEN);
+ (*env)->ReleaseStringChars(env, jStr, pjChar);
+
+ if (got) {
+ return (*env)->NewString(env, buf, wcslen(buf));
+ } else {
+ return NULL;
+ }
+}
+
int getLocaleInfoWrapper(const jchar *langtag, LCTYPE type, LPWSTR data, int buflen) {
if (pGetLocaleInfoEx) {
if (wcscmp(L"und", (LPWSTR)langtag) == 0) {
@@ -642,11 +691,13 @@
}
jint getCalendarID(const jchar *langtag) {
- WCHAR type[BUFLEN];
- int got = getLocaleInfoWrapper(langtag, LOCALE_ICALENDARTYPE, type, BUFLEN);
+ DWORD type;
+ int got = getLocaleInfoWrapper(langtag,
+ LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&type, sizeof(type));
if (got) {
- return _wtoi(type);
+ return type;
} else {
return 0;
}
@@ -691,28 +742,37 @@
}
void getNumberPart(const jchar * langtag, const jint numberStyle, WCHAR * number) {
- WCHAR buf[BUFLEN];
+ DWORD digits = 0;
+ DWORD leadingZero = 0;
WCHAR grouping[BUFLEN];
+ int groupingLen;
WCHAR fractionPattern[BUFLEN];
WCHAR * integerPattern = number;
- int digits;
- BOOL leadingZero;
WCHAR * pDest;
- int groupingLen;
// Get info from Windows
- if (numberStyle == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {
- getLocaleInfoWrapper(langtag, LOCALE_ICURRDIGITS, buf, BUFLEN);
- } else {
- getLocaleInfoWrapper(langtag, LOCALE_IDIGITS, buf, BUFLEN);
+ switch (numberStyle) {
+ case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY:
+ getLocaleInfoWrapper(langtag,
+ LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&digits, sizeof(digits));
+ break;
+
+ case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER:
+ break;
+
+ case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER:
+ case sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT:
+ default:
+ getLocaleInfoWrapper(langtag,
+ LOCALE_IDIGITS | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&digits, sizeof(digits));
+ break;
}
- if (numberStyle == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER) {
- digits = 0;
- } else {
- digits = _wtoi(buf);
- }
- getLocaleInfoWrapper(langtag, LOCALE_ILZERO, buf, BUFLEN);
- leadingZero = _wtoi(buf) != 0;
+
+ getLocaleInfoWrapper(langtag,
+ LOCALE_ILZERO | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&leadingZero, sizeof(leadingZero));
groupingLen = getLocaleInfoWrapper(langtag, LOCALE_SGROUPING, grouping, BUFLEN);
// fraction pattern
@@ -749,7 +809,7 @@
}
}
- if (leadingZero) {
+ if (leadingZero != 0) {
*pDest++ = L'0';
} else {
*pDest++ = L'#';
@@ -760,29 +820,35 @@
}
void getFixPart(const jchar * langtag, const jint numberStyle, BOOL positive, BOOL prefix, WCHAR * ret) {
- WCHAR buf[BUFLEN];
- int pattern = 0;
+ DWORD pattern = 0;
int style = numberStyle;
int got = 0;
if (positive) {
if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {
- got = getLocaleInfoWrapper(langtag, LOCALE_ICURRENCY, buf, BUFLEN);
+ got = getLocaleInfoWrapper(langtag,
+ LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&pattern, sizeof(pattern));
} else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {
- got = getLocaleInfoWrapper(langtag, LOCALE_IPOSITIVEPERCENT, buf, BUFLEN);
+ got = getLocaleInfoWrapper(langtag,
+ LOCALE_IPOSITIVEPERCENT | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&pattern, sizeof(pattern));
}
} else {
if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_CURRENCY) {
- got = getLocaleInfoWrapper(langtag, LOCALE_INEGCURR, buf, BUFLEN);
+ got = getLocaleInfoWrapper(langtag,
+ LOCALE_INEGCURR | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&pattern, sizeof(pattern));
} else if (style == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_PERCENT) {
- got = getLocaleInfoWrapper(langtag, LOCALE_INEGATIVEPERCENT, buf, BUFLEN);
+ got = getLocaleInfoWrapper(langtag,
+ LOCALE_INEGATIVEPERCENT | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&pattern, sizeof(pattern));
} else {
- got = getLocaleInfoWrapper(langtag, LOCALE_INEGNUMBER, buf, BUFLEN);
+ got = getLocaleInfoWrapper(langtag,
+ LOCALE_INEGNUMBER | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&pattern, sizeof(pattern));
}
}
- if (got) {
- pattern = _wtoi(buf);
- }
if (numberStyle == sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_INTEGER) {
style = sun_util_locale_provider_HostLocaleProviderAdapterImpl_NF_NUMBER;
--- a/jdk/test/java/util/Locale/LocaleProviders.java Wed Apr 17 11:34:31 2013 +0200
+++ b/jdk/test/java/util/Locale/LocaleProviders.java Mon Apr 22 13:37:07 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -23,6 +23,7 @@
import java.text.*;
import java.text.spi.*;
import java.util.*;
+import java.util.spi.*;
import sun.util.locale.provider.LocaleProviderAdapter;
public class LocaleProviders {
@@ -55,6 +56,10 @@
bug8001440Test();
break;
+ case "bug8010666Test":
+ bug8010666Test();
+ break;
+
default:
throw new RuntimeException("Test method '"+methodName+"' not found.");
}
@@ -103,4 +108,38 @@
NumberFormat nf = NumberFormat.getInstance(locale);
String nu = nf.format(1234560);
}
+
+ // This test assumes Windows localized language/country display names.
+ static void bug8010666Test() {
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ NumberFormat nf = NumberFormat.getInstance(Locale.US);
+ try {
+ double ver = nf.parse(System.getProperty("os.version")).doubleValue();
+ System.out.printf("Windows version: %.1f\n", ver);
+ if (ver >= 6.0) {
+ LocaleProviderAdapter lda = LocaleProviderAdapter.getAdapter(LocaleNameProvider.class, Locale.ENGLISH);
+ LocaleProviderAdapter.Type type = lda.getAdapterType();
+ if (type == LocaleProviderAdapter.Type.HOST) {
+ Locale mkmk = Locale.forLanguageTag("mk-MK");
+ String result = mkmk.getDisplayLanguage(Locale.ENGLISH);
+ if (!"Macedonian (FYROM)".equals(result)) {
+ throw new RuntimeException("Windows locale name provider did not return expected localized language name for \"mk\". Returned name was \"" + result + "\"");
+ }
+ result = Locale.US.getDisplayLanguage(Locale.ENGLISH);
+ if (!"English".equals(result)) {
+ throw new RuntimeException("Windows locale name provider did not return expected localized language name for \"en\". Returned name was \"" + result + "\"");
+ }
+ result = Locale.US.getDisplayCountry(Locale.ENGLISH);
+ if (ver >= 6.1 && !"United States".equals(result)) {
+ throw new RuntimeException("Windows locale name provider did not return expected localized country name for \"US\". Returned name was \"" + result + "\"");
+ }
+ } else {
+ throw new RuntimeException("Windows Host LocaleProviderAdapter was not selected for English locale.");
+ }
+ }
+ } catch (ParseException pe) {
+ throw new RuntimeException("Parsing Windows version failed: "+pe.toString());
+ }
+ }
+ }
}
--- a/jdk/test/java/util/Locale/LocaleProviders.sh Wed Apr 17 11:34:31 2013 +0200
+++ b/jdk/test/java/util/Locale/LocaleProviders.sh Mon Apr 22 13:37:07 2013 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2013, 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
@@ -23,7 +23,7 @@
#!/bin/sh
#
# @test
-# @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440
+# @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8010666
# @summary tests for "java.locale.providers" system property
# @compile -XDignore.symbol.file LocaleProviders.java
# @run shell/timeout=600 LocaleProviders.sh
@@ -258,4 +258,15 @@
PARAM3=
runTest
+# testing 8010666 fix.
+if [ "${DEFLANG}" = "en" ]
+then
+ METHODNAME=bug8010666Test
+ PREFLIST=HOST
+ PARAM1=
+ PARAM2=
+ PARAM3=
+ runTest
+fi
+
exit $result