--- old/make/java/java/FILES_java.gmk Thu Sep 20 15:20:38 2012 +++ new/make/java/java/FILES_java.gmk Thu Sep 20 15:20:36 2012 @@ -213,6 +213,7 @@ sun/util/locale/provider/DateFormatSymbolsProviderImpl.java \ sun/util/locale/provider/DecimalFormatSymbolsProviderImpl.java \ sun/util/locale/provider/DictionaryBasedBreakIterator.java \ + sun/util/locale/provider/FallbackLocaleProviderAdapter.java \ sun/util/locale/provider/HostLocaleProviderAdapter.java \ sun/util/locale/provider/HostLocaleProviderAdapterImpl.java \ sun/util/locale/provider/JRELocaleConstants.java \ --- old/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java Thu Sep 20 15:20:44 2012 +++ new/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java Thu Sep 20 15:20:43 2012 @@ -71,7 +71,7 @@ */ @Override public LocaleProviderAdapter.Type getAdapterType() { - return LocaleProviderAdapter.Type.JRE; + return Type.JRE; } /** --- old/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java Thu Sep 20 15:20:52 2012 +++ new/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java Thu Sep 20 15:20:50 2012 @@ -59,7 +59,8 @@ JRE("sun.util.resources", "sun.text.resources"), CLDR("sun.util.resources.cldr", "sun.text.resources.cldr"), SPI, - HOST; + HOST, + FALLBACK("sun.util.resources", "sun.text.resources"); private final String UTIL_RESOURCES_PACKAGE; private final String TEXT_RESOURCES_PACKAGE; @@ -111,41 +112,47 @@ */ private static LocaleProviderAdapter hostLocaleProviderAdapter = null; + /** + * FALLBACK Locale Data Adapter instance. It's basically the same with JRE, but only kicks + * in for the root locale. + */ + private static LocaleProviderAdapter fallbackLocaleProviderAdapter = null; + static { String order = AccessController.doPrivileged( new sun.security.action.GetPropertyAction("java.locale.providers")); - // Override adapterPreference with the properties one - if (order != null && order.length() != 0) { - String[] types = order.split(","); - List typeList = new ArrayList<>(); - for (String type : types) { - try { - Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT)); + // Override adapterPreference with the properties one + if (order != null && order.length() != 0) { + String[] types = order.split(","); + List typeList = new ArrayList<>(); + for (String type : types) { + try { + Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT)); - // load adapter if necessary - switch (aType) { - case CLDR: - cldrLocaleProviderAdapter = new CLDRLocaleProviderAdapter(); - break; - case HOST: - hostLocaleProviderAdapter = new HostLocaleProviderAdapter(); - break; - } - typeList.add(aType); - } catch (// could be caused by the user specifying wrong - // provider name or format in the system property - IllegalArgumentException | - UnsupportedOperationException e) { - LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString()); - } - } - - if (!typeList.contains(Type.JRE)) { - // Append JRE as the last resort. - typeList.add(Type.JRE); - } - adapterPreference = typeList.toArray(new Type[0]); + // load adapter if necessary + switch (aType) { + case CLDR: + cldrLocaleProviderAdapter = new CLDRLocaleProviderAdapter(); + break; + case HOST: + hostLocaleProviderAdapter = new HostLocaleProviderAdapter(); + break; } + typeList.add(aType); + } catch (IllegalArgumentException | UnsupportedOperationException e) { + // could be caused by the user specifying wrong + // provider name or format in the system property + LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString()); + } + } + + if (!typeList.contains(Type.JRE)) { + // Append FALLBACK as the last resort. + fallbackLocaleProviderAdapter = new FallbackLocaleProviderAdapter(); + typeList.add(Type.FALLBACK); + } + adapterPreference = typeList.toArray(new Type[0]); + } } @@ -162,6 +169,8 @@ return spiLocaleProviderAdapter; case HOST: return hostLocaleProviderAdapter; + case FALLBACK: + return fallbackLocaleProviderAdapter; default: throw new InternalError("unknown locale data adapter type"); } @@ -173,7 +182,7 @@ public static LocaleProviderAdapter getResourceBundleBased() { for (Type type : getAdapterPreference()) { - if (type == Type.JRE || type == Type.CLDR) { + if (type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK) { return forType(type); } } @@ -218,8 +227,11 @@ } } - // returns the adapter for JRE as the last resort - return jreLocaleProviderAdapter; + // returns the adapter for FALLBACK as the last resort + if (fallbackLocaleProviderAdapter == null) { + fallbackLocaleProviderAdapter = new FallbackLocaleProviderAdapter(); + } + return fallbackLocaleProviderAdapter; } private static LocaleProviderAdapter findAdapter(Class providerClass, @@ -238,18 +250,24 @@ /** * A utility method for implementing the default LocaleServiceProvider.isSupportedLocale - * for the JRE and CLDR adapters. + * for the JRE, CLDR, and FALLBACK adapters. */ static boolean isSupportedLocale(Locale locale, LocaleProviderAdapter.Type type, Set langtags) { - assert type == Type.JRE || type == Type.CLDR; + assert type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK; if (locale == Locale.ROOT) { return true; } + + if (type == Type.FALLBACK) { + // no other locales except ROOT are supported for FALLBACK + return false; + } + locale = locale.stripExtensions(); if (langtags.contains(locale.toLanguageTag())) { return true; } - if (type == LocaleProviderAdapter.Type.JRE) { + if (type == Type.JRE) { String oldname = locale.toString().replace('_', '-'); return langtags.contains(oldname); } --- old/test/java/util/Locale/LocaleProviders.java Thu Sep 20 15:20:59 2012 +++ new/test/java/util/Locale/LocaleProviders.java Thu Sep 20 15:20:57 2012 @@ -27,14 +27,20 @@ public class LocaleProviders { public static void main(String[] args) { - String expected = args[0]; - Locale testLocale = new Locale(args[1], args[2]); - String preference = System.getProperty("java.locale.providers", ""); - LocaleProviderAdapter lda = LocaleProviderAdapter.getAdapter(DateFormatProvider.class, testLocale); - LocaleProviderAdapter.Type type = lda.getAdapterType(); - System.out.printf("testLocale: %s, got: %s, expected: %s\n", testLocale, type, expected); - if (!type.toString().equals(expected)) { - throw new RuntimeException("Returned locale data adapter is not correct."); + if (args.length == 0) { + // no args indicates that the caller is asking the platform default locale. + Locale defloc = Locale.getDefault(); + System.out.printf("%s,%s\n", defloc.getLanguage(), defloc.getCountry()); + } else { + String expected = args[0]; + Locale testLocale = new Locale(args[1], (args.length >= 3 ? args[2] : "")); + String preference = System.getProperty("java.locale.providers", ""); + LocaleProviderAdapter lda = LocaleProviderAdapter.getAdapter(DateFormatProvider.class, testLocale); + LocaleProviderAdapter.Type type = lda.getAdapterType(); + System.out.printf("testLocale: %s, got: %s, expected: %s\n", testLocale, type, expected); + if (!type.toString().equals(expected)) { + throw new RuntimeException("Returned locale data adapter is not correct."); + } } } } --- old/test/java/util/Locale/LocaleProviders.sh Thu Sep 20 15:21:07 2012 +++ new/test/java/util/Locale/LocaleProviders.sh Thu Sep 20 15:21:05 2012 @@ -23,7 +23,7 @@ #!/bin/sh # # @test -# @bug 6336885 +# @bug 6336885 7196799 7197573 # @summary tests for "java.locale.providers" system property # @compile -XDignore.symbol.file LocaleProviders.java # @run shell/timeout=600 LocaleProviders.sh @@ -65,9 +65,16 @@ ;; esac +# get the platform default locale +PLATDEF=`${TESTJAVA}${FS}bin${FS}java -classpath ${TESTCLASSES} LocaleProviders` +DEFLANG=`echo ${PLATDEF} | sed -e "s/,.*//"` +DEFCTRY=`echo ${PLATDEF} | sed -e "s/.*,//"` +echo "DEFLANG=${DEFLANG}" +echo "DEFCTRY=${DEFCTRY}" + runTest() { - RUNCMD="${TESTJAVA}${FS}bin${FS}java -classpath ${TESTCLASSES} -Duser.language=$DEFLANG -Duser.country=$DEFCTRY -Djava.locale.providers=$PREFLIST LocaleProviders $EXPECTED $TESTLANG $TESTCTRY" + RUNCMD="${TESTJAVA}${FS}bin${FS}java -classpath ${TESTCLASSES} -Djava.locale.providers=$PREFLIST LocaleProviders $EXPECTED $TESTLANG $TESTCTRY" echo ${RUNCMD} ${RUNCMD} result=$? @@ -81,9 +88,7 @@ } # testing HOST is selected for the default locale, if specified on Windows or MacOSX -DEFLANG=en -DEFCTRY=US -PREFLIST=HOST +PREFLIST=HOST,JRE case "$OS" in Windows_NT* ) WINVER=`uname -r` @@ -101,21 +106,25 @@ EXPECTED=JRE ;; esac -TESTLANG=en -TESTCTRY=US +TESTLANG=${DEFLANG} +TESTCTRY=${DEFCTRY} runTest # testing HOST is NOT selected for the non-default locale, if specified -DEFLANG=en -DEFCTRY=US -PREFLIST=HOST +PREFLIST=HOST,JRE EXPECTED=JRE -TESTLANG=en -TESTCTRY=GB +if [ "${DEFLANG}" = "en" ] +then + TESTLANG=ja + TESTCTRY=JP +else + TESTLANG=en + TESTCTRY=US +fi runTest # testing SPI is NOT selected, as there is none. -PREFLIST=SPI +PREFLIST=SPI,JRE EXPECTED=JRE TESTLANG=en TESTCTRY=US @@ -122,7 +131,7 @@ runTest # testing the order, variaton #1. This assumes en_GB DateFormat data are available both in JRE & CLDR -PREFLIST=CLDR +PREFLIST=CLDR,JRE EXPECTED=CLDR TESTLANG=en TESTCTRY=GB @@ -142,4 +151,23 @@ TESTCTRY=GB runTest +# testing the order, variaton #4 for the bug 7196799. CLDR's "zh" data should be used in "zh_CN" +PREFLIST=CLDR +EXPECTED=CLDR +TESTLANG=zh +TESTCTRY=CN +runTest + +# testing FALLBACK provider. SPI and invalid one cases. +PREFLIST=SPI +EXPECTED=FALLBACK +TESTLANG=en +TESTCTRY=US +runTest +PREFLIST=FOO +EXPECTED=FALLBACK +TESTLANG=en +TESTCTRY=US +runTest + exit $result --- /dev/null Thu Sep 20 15:21:13 2012 +++ new/src/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java Thu Sep 20 15:21:11 2012 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.locale.provider; + +/** + * FallbackProviderAdapter implementation. + * + * @author Naoto Sato + */ +public class FallbackLocaleProviderAdapter extends JRELocaleProviderAdapter { + + /** + * Returns the type of this LocaleProviderAdapter + */ + @Override + public LocaleProviderAdapter.Type getAdapterType() { + return Type.FALLBACK; + } +}