# HG changeset patch # User okutsu # Date 1302764387 -32400 # Node ID 75c0420badef13e0a04fa8f24025caa404d88979 # Parent d331b7996fc394573a0eb015411323a62fac4705 7028818: (lc) Lazily initialize locale extension 7029740: (lc) New Locale class implementation doesn't follow the Java coding conventions 7032820: (lc) sun.util.locale.InternalLocaleBuilder.CaseInsensitiveChar.equals problems 7033503: (lc) Restore optimization code for Locale class initialization 7033504: (lc) incompatible behavior change for ja_JP_JP and th_TH_TH locales Reviewed-by: naoto diff -r d331b7996fc3 -r 75c0420badef jdk/make/java/java/FILES_java.gmk --- a/jdk/make/java/java/FILES_java.gmk Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/make/java/java/FILES_java.gmk Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1996, 2011, 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 @@ -189,7 +189,6 @@ java/util/ListResourceBundle.java \ sun/util/EmptyListResourceBundle.java \ java/util/Locale.java \ - sun/util/locale/AsciiUtil.java \ sun/util/locale/BaseLocale.java \ sun/util/locale/Extension.java \ sun/util/locale/InternalLocaleBuilder.java \ @@ -197,6 +196,7 @@ sun/util/locale/LocaleExtensions.java \ sun/util/locale/LocaleObjectCache.java \ sun/util/locale/LocaleSyntaxException.java \ + sun/util/locale/LocaleUtils.java \ sun/util/locale/ParseStatus.java \ sun/util/locale/StringTokenIterator.java \ sun/util/locale/UnicodeLocaleExtension.java \ diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/java/util/Locale.java --- a/jdk/src/share/classes/java/util/Locale.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/java/util/Locale.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, 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 @@ -51,13 +51,13 @@ import sun.security.action.GetPropertyAction; import sun.util.LocaleServiceProviderPool; -import sun.util.locale.AsciiUtil; import sun.util.locale.BaseLocale; import sun.util.locale.InternalLocaleBuilder; import sun.util.locale.LanguageTag; import sun.util.locale.LocaleExtensions; import sun.util.locale.LocaleObjectCache; import sun.util.locale.LocaleSyntaxException; +import sun.util.locale.LocaleUtils; import sun.util.locale.ParseStatus; import sun.util.locale.UnicodeLocaleExtension; import sun.util.resources.LocaleData; @@ -412,59 +412,59 @@ /** Useful constant for language. */ - static public final Locale ENGLISH = getInstance("en", "", ""); + static public final Locale ENGLISH = createConstant("en", ""); /** Useful constant for language. */ - static public final Locale FRENCH = getInstance("fr", "", ""); + static public final Locale FRENCH = createConstant("fr", ""); /** Useful constant for language. */ - static public final Locale GERMAN = getInstance("de", "", ""); + static public final Locale GERMAN = createConstant("de", ""); /** Useful constant for language. */ - static public final Locale ITALIAN = getInstance("it", "", ""); + static public final Locale ITALIAN = createConstant("it", ""); /** Useful constant for language. */ - static public final Locale JAPANESE = getInstance("ja", "", ""); + static public final Locale JAPANESE = createConstant("ja", ""); /** Useful constant for language. */ - static public final Locale KOREAN = getInstance("ko", "", ""); + static public final Locale KOREAN = createConstant("ko", ""); /** Useful constant for language. */ - static public final Locale CHINESE = getInstance("zh", "", ""); + static public final Locale CHINESE = createConstant("zh", ""); /** Useful constant for language. */ - static public final Locale SIMPLIFIED_CHINESE = getInstance("zh", "CN", ""); + static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN"); /** Useful constant for language. */ - static public final Locale TRADITIONAL_CHINESE = getInstance("zh", "TW", ""); + static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW"); /** Useful constant for country. */ - static public final Locale FRANCE = getInstance("fr", "FR", ""); + static public final Locale FRANCE = createConstant("fr", "FR"); /** Useful constant for country. */ - static public final Locale GERMANY = getInstance("de", "DE", ""); + static public final Locale GERMANY = createConstant("de", "DE"); /** Useful constant for country. */ - static public final Locale ITALY = getInstance("it", "IT", ""); + static public final Locale ITALY = createConstant("it", "IT"); /** Useful constant for country. */ - static public final Locale JAPAN = getInstance("ja", "JP", ""); + static public final Locale JAPAN = createConstant("ja", "JP"); /** Useful constant for country. */ - static public final Locale KOREA = getInstance("ko", "KR", ""); + static public final Locale KOREA = createConstant("ko", "KR"); /** Useful constant for country. */ @@ -480,19 +480,19 @@ /** Useful constant for country. */ - static public final Locale UK = getInstance("en", "GB", ""); + static public final Locale UK = createConstant("en", "GB"); /** Useful constant for country. */ - static public final Locale US = getInstance("en", "US", ""); + static public final Locale US = createConstant("en", "US"); /** Useful constant for country. */ - static public final Locale CANADA = getInstance("en", "CA", ""); + static public final Locale CANADA = createConstant("en", "CA"); /** Useful constant for country. */ - static public final Locale CANADA_FRENCH = getInstance("fr", "CA", ""); + static public final Locale CANADA_FRENCH = createConstant("fr", "CA"); /** * Useful constant for the root locale. The root locale is the locale whose @@ -502,7 +502,7 @@ * * @since 1.6 */ - static public final Locale ROOT = getInstance("", "", ""); + static public final Locale ROOT = createConstant("", ""); /** * The key for the private use extension ('x'). @@ -532,14 +532,14 @@ private static final int DISPLAY_LANGUAGE = 0; private static final int DISPLAY_COUNTRY = 1; private static final int DISPLAY_VARIANT = 2; - private static final int DISPLAY_SCRIPT = 3; + private static final int DISPLAY_SCRIPT = 3; /** * Private constructor used by getInstance method */ private Locale(BaseLocale baseLocale, LocaleExtensions extensions) { - _baseLocale = baseLocale; - _extensions = extensions; + this.baseLocale = baseLocale; + this.localeExtensions = extensions; } /** @@ -572,8 +572,8 @@ if (language== null || country == null || variant == null) { throw new NullPointerException(); } - _baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant); - _extensions = getCompatibilityExtensions(language, "", country, variant); + baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant); + localeExtensions = getCompatibilityExtensions(language, "", country, variant); } /** @@ -627,6 +627,15 @@ } /** + * This method must be called only for creating the Locale.* + * constants due to making shortcuts. + */ + private static Locale createConstant(String lang, String country) { + BaseLocale base = BaseLocale.createInstance(lang, country); + return getInstance(base, null); + } + + /** * Returns a Locale constructed from the given * language, country and * variant. If the same Locale instance @@ -641,7 +650,7 @@ * @exception NullPointerException if any argument is null. */ static Locale getInstance(String language, String country, String variant) { - return getInstance(language, "", country, variant, LocaleExtensions.EMPTY_EXTENSIONS); + return getInstance(language, "", country, variant, null); } static Locale getInstance(String language, String script, String country, @@ -651,10 +660,6 @@ } if (extensions == null) { - extensions = LocaleExtensions.EMPTY_EXTENSIONS; - } - - if (extensions.equals(LocaleExtensions.EMPTY_EXTENSIONS)) { extensions = getCompatibilityExtensions(language, script, country, variant); } @@ -668,22 +673,33 @@ } private static class Cache extends LocaleObjectCache { - public Cache() { + private Cache() { } + + @Override protected Locale createObject(LocaleKey key) { - return new Locale(key._base, key._exts); + return new Locale(key.base, key.exts); } } - private static class LocaleKey { - private BaseLocale _base; - private LocaleExtensions _exts; + private static final class LocaleKey { + private final BaseLocale base; + private final LocaleExtensions exts; + private final int hash; private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) { - _base = baseLocale; - _exts = extensions; + base = baseLocale; + exts = extensions; + + // Calculate the hash value here because it's always used. + int h = base.hashCode(); + if (exts != null) { + h ^= exts.hashCode(); + } + hash = h; } + @Override public boolean equals(Object obj) { if (this == obj) { return true; @@ -692,11 +708,18 @@ return false; } LocaleKey other = (LocaleKey)obj; - return _base.equals(other._base) && _exts.equals(other._exts); + if (hash != other.hash || !base.equals(other.base)) { + return false; + } + if (exts == null) { + return other.exts == null; + } + return exts.equals(other.exts); } + @Override public int hashCode() { - return _base.hashCode() ^ _exts.hashCode(); + return hash; } } @@ -981,7 +1004,7 @@ * @see #getDisplayLanguage */ public String getLanguage() { - return _baseLocale.getLanguage(); + return baseLocale.getLanguage(); } /** @@ -995,7 +1018,7 @@ * @since 1.7 */ public String getScript() { - return _baseLocale.getScript(); + return baseLocale.getScript(); } /** @@ -1007,7 +1030,7 @@ * @see #getDisplayCountry */ public String getCountry() { - return _baseLocale.getRegion(); + return baseLocale.getRegion(); } /** @@ -1017,7 +1040,7 @@ * @see #getDisplayVariant */ public String getVariant() { - return _baseLocale.getVariant(); + return baseLocale.getVariant(); } /** @@ -1039,7 +1062,7 @@ if (!LocaleExtensions.isValidKey(key)) { throw new IllegalArgumentException("Ill-formed extension key: " + key); } - return _extensions.getExtensionValue(key); + return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key); } /** @@ -1052,7 +1075,10 @@ * @since 1.7 */ public Set getExtensionKeys() { - return _extensions.getKeys(); + if (localeExtensions == null) { + return Collections.emptySet(); + } + return localeExtensions.getKeys(); } /** @@ -1064,7 +1090,10 @@ * @since 1.7 */ public Set getUnicodeLocaleAttributes() { - return _extensions.getUnicodeLocaleAttributes(); + if (localeExtensions == null) { + return Collections.emptySet(); + } + return localeExtensions.getUnicodeLocaleAttributes(); } /** @@ -1085,7 +1114,7 @@ if (!UnicodeLocaleExtension.isKey(key)) { throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key); } - return _extensions.getUnicodeLocaleType(key); + return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key); } /** @@ -1097,7 +1126,10 @@ * @since 1.7 */ public Set getUnicodeLocaleKeys() { - return _extensions.getUnicodeLocaleKeys(); + if (localeExtensions == null) { + return Collections.emptySet(); + } + return localeExtensions.getUnicodeLocaleKeys(); } /** @@ -1106,16 +1138,17 @@ * @return base locale of this Locale */ BaseLocale getBaseLocale() { - return _baseLocale; + return baseLocale; } /** - * Package local method returning the Locale's LocaleExtensions, - * used by ResourceBundle - * @return locale exnteions of this Locale + * Package private method returning the Locale's LocaleExtensions, + * used by ResourceBundle. + * @return locale exnteions of this Locale, + * or {@code null} if no extensions are defined */ LocaleExtensions getLocaleExtensions() { - return _extensions; + return localeExtensions; } /** @@ -1160,26 +1193,27 @@ * @see #getDisplayName * @see #toLanguageTag */ + @Override public final String toString() { - boolean l = (_baseLocale.getLanguage().length() != 0); - boolean s = (_baseLocale.getScript().length() != 0); - boolean r = (_baseLocale.getRegion().length() != 0); - boolean v = (_baseLocale.getVariant().length() != 0); - boolean e = (_extensions.getID().length() != 0); + boolean l = (baseLocale.getLanguage().length() != 0); + boolean s = (baseLocale.getScript().length() != 0); + boolean r = (baseLocale.getRegion().length() != 0); + boolean v = (baseLocale.getVariant().length() != 0); + boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0); - StringBuilder result = new StringBuilder(_baseLocale.getLanguage()); + StringBuilder result = new StringBuilder(baseLocale.getLanguage()); if (r || (l && (v || s || e))) { result.append('_') - .append(_baseLocale.getRegion()); // This may just append '_' + .append(baseLocale.getRegion()); // This may just append '_' } if (v && (l || r)) { result.append('_') - .append(_baseLocale.getVariant()); + .append(baseLocale.getVariant()); } if (s && (l || r)) { result.append("_#") - .append(_baseLocale.getScript()); + .append(baseLocale.getScript()); } if (e && (l || r)) { @@ -1187,7 +1221,7 @@ if (!s) { result.append('#'); } - result.append(_extensions.getID()); + result.append(localeExtensions.getID()); } return result.toString(); @@ -1261,7 +1295,7 @@ * @since 1.7 */ public String toLanguageTag() { - LanguageTag tag = LanguageTag.parseLocale(_baseLocale, _extensions); + LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions); StringBuilder buf = new StringBuilder(); String subtag = tag.getLanguage(); @@ -1433,8 +1467,9 @@ bldr.setLanguageTag(tag); BaseLocale base = bldr.getBaseLocale(); LocaleExtensions exts = bldr.getLocaleExtensions(); - if (exts.isEmpty() && base.getVariant().length() > 0) { - exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(), base.getRegion(), base.getVariant()); + if (exts == null && base.getVariant().length() > 0) { + exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(), + base.getRegion(), base.getVariant()); } return getInstance(base, exts); } @@ -1454,7 +1489,7 @@ * three-letter language abbreviation is not available for this locale. */ public String getISO3Language() throws MissingResourceException { - String lang = _baseLocale.getLanguage(); + String lang = baseLocale.getLanguage(); if (lang.length() == 3) { return lang; } @@ -1481,10 +1516,10 @@ * three-letter country abbreviation is not available for this locale. */ public String getISO3Country() throws MissingResourceException { - String country3 = getISO3Code(_baseLocale.getRegion(), LocaleISOData.isoCountryTable); + String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable); if (country3 == null) { throw new MissingResourceException("Couldn't find 3-letter country code for " - + _baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry"); + + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry"); } return country3; } @@ -1542,7 +1577,7 @@ * @exception NullPointerException if inLocale is null */ public String getDisplayLanguage(Locale inLocale) { - return getDisplayString(_baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE); + return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE); } /** @@ -1568,7 +1603,7 @@ * @since 1.7 */ public String getDisplayScript(Locale inLocale) { - return getDisplayString(_baseLocale.getScript(), inLocale, DISPLAY_SCRIPT); + return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT); } /** @@ -1603,7 +1638,7 @@ * @exception NullPointerException if inLocale is null */ public String getDisplayCountry(Locale inLocale) { - return getDisplayString(_baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY); + return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY); } private String getDisplayString(String code, Locale inLocale, int type) { @@ -1662,7 +1697,7 @@ * @exception NullPointerException if inLocale is null */ public String getDisplayVariant(Locale inLocale) { - if (_baseLocale.getVariant().length() == 0) + if (baseLocale.getVariant().length() == 0) return ""; OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale); @@ -1758,7 +1793,7 @@ return formatList(variantNames, listPattern, listCompositionPattern); } } - ArrayList names = new ArrayList(4); + ArrayList names = new ArrayList<>(4); if (languageName.length() != 0) { names.add(languageName); } @@ -1833,10 +1868,14 @@ * Since Locales are often used in hashtables, caches the value * for speed. */ + @Override public int hashCode() { int hc = hashCodeValue; if (hc == 0) { - hc = _baseLocale.hashCode() ^ _extensions.hashCode(); + hc = baseLocale.hashCode(); + if (localeExtensions != null) { + hc ^= localeExtensions.hashCode(); + } hashCodeValue = hc; } return hc; @@ -1851,21 +1890,26 @@ * * @return true if this Locale is equal to the specified object. */ - + @Override public boolean equals(Object obj) { if (this == obj) // quick check return true; if (!(obj instanceof Locale)) return false; - BaseLocale otherBase = ((Locale)obj)._baseLocale; - LocaleExtensions otherExt = ((Locale)obj)._extensions; - return _baseLocale.equals(otherBase) && _extensions.equals(otherExt); + BaseLocale otherBase = ((Locale)obj).baseLocale; + if (!baseLocale.equals(otherBase)) { + return false; + } + if (localeExtensions == null) { + return ((Locale)obj).localeExtensions == null; + } + return localeExtensions.equals(((Locale)obj).localeExtensions); } // ================= privates ===================================== - private transient BaseLocale _baseLocale; - private transient LocaleExtensions _extensions; + private transient BaseLocale baseLocale; + private transient LocaleExtensions localeExtensions; /** * Calculated hashcode @@ -1883,7 +1927,7 @@ */ private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) { // Split the variant name into tokens separated by '_'. - StringTokenizer tokenizer = new StringTokenizer(_baseLocale.getVariant(), "_"); + StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_"); String[] names = new String[tokenizer.countTokens()]; // For each variant token, lookup the display name. If @@ -1996,11 +2040,11 @@ */ private void writeObject(ObjectOutputStream out) throws IOException { ObjectOutputStream.PutField fields = out.putFields(); - fields.put("language", _baseLocale.getLanguage()); - fields.put("script", _baseLocale.getScript()); - fields.put("country", _baseLocale.getRegion()); - fields.put("variant", _baseLocale.getVariant()); - fields.put("extensions", _extensions.getID()); + fields.put("language", baseLocale.getLanguage()); + fields.put("script", baseLocale.getScript()); + fields.put("country", baseLocale.getRegion()); + fields.put("variant", baseLocale.getVariant()); + fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID()); fields.put("hashcode", -1); // place holder just for backward support out.writeFields(); } @@ -2020,13 +2064,17 @@ String country = (String)fields.get("country", ""); String variant = (String)fields.get("variant", ""); String extStr = (String)fields.get("extensions", ""); - _baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); - try { - InternalLocaleBuilder bldr = new InternalLocaleBuilder(); - bldr.setExtensions(extStr); - _extensions = bldr.getLocaleExtensions(); - } catch (LocaleSyntaxException e) { - throw new IllformedLocaleException(e.getMessage()); + baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); + if (extStr.length() > 0) { + try { + InternalLocaleBuilder bldr = new InternalLocaleBuilder(); + bldr.setExtensions(extStr); + localeExtensions = bldr.getLocaleExtensions(); + } catch (LocaleSyntaxException e) { + throw new IllformedLocaleException(e.getMessage()); + } + } else { + localeExtensions = null; } } @@ -2045,8 +2093,8 @@ * @throws java.io.ObjectStreamException */ private Object readResolve() throws java.io.ObjectStreamException { - return getInstance(_baseLocale.getLanguage(), _baseLocale.getScript(), - _baseLocale.getRegion(), _baseLocale.getVariant(), _extensions); + return getInstance(baseLocale.getLanguage(), baseLocale.getScript(), + baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions); } private static volatile String[] isoLanguages = null; @@ -2056,7 +2104,7 @@ private static String convertOldISOCodes(String language) { // we accept both the old and the new ISO codes for the languages whose ISO // codes have changed, but we always store the OLD code, for backward compatibility - language = AsciiUtil.toLowerString(language).intern(); + language = LocaleUtils.toLowerString(language).intern(); if (language == "he") { return "iw"; } else if (language == "yi") { @@ -2068,19 +2116,22 @@ } } - private static LocaleExtensions getCompatibilityExtensions(String language, String script, String country, String variant) { - LocaleExtensions extensions = LocaleExtensions.EMPTY_EXTENSIONS; + private static LocaleExtensions getCompatibilityExtensions(String language, + String script, + String country, + String variant) { + LocaleExtensions extensions = null; // Special cases for backward compatibility support - if (AsciiUtil.caseIgnoreMatch(language, "ja") + if (LocaleUtils.caseIgnoreMatch(language, "ja") && script.length() == 0 - && AsciiUtil.caseIgnoreMatch(country, "JP") - && AsciiUtil.caseIgnoreMatch(variant, "JP")) { + && LocaleUtils.caseIgnoreMatch(country, "jp") + && "JP".equals(variant)) { // ja_JP_JP -> u-ca-japanese (calendar = japanese) extensions = LocaleExtensions.CALENDAR_JAPANESE; - } else if (AsciiUtil.caseIgnoreMatch(language, "th") + } else if (LocaleUtils.caseIgnoreMatch(language, "th") && script.length() == 0 - && AsciiUtil.caseIgnoreMatch(country, "TH") - && AsciiUtil.caseIgnoreMatch(variant, "TH")) { + && LocaleUtils.caseIgnoreMatch(country, "th") + && "TH".equals(variant)) { // th_TH_TH -> u-nu-thai (numbersystem = thai) extensions = LocaleExtensions.NUMBER_THAI; } @@ -2196,7 +2247,7 @@ * @since 1.7 */ public static final class Builder { - private InternalLocaleBuilder _locbld; + private final InternalLocaleBuilder localeBuilder; /** * Constructs an empty Builder. The default value of all @@ -2204,7 +2255,7 @@ * empty string. */ public Builder() { - _locbld = new InternalLocaleBuilder(); + localeBuilder = new InternalLocaleBuilder(); } /** @@ -2229,7 +2280,7 @@ */ public Builder setLocale(Locale locale) { try { - _locbld.setLocale(locale._baseLocale, locale._extensions); + localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2259,8 +2310,7 @@ if (sts.isError()) { throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex()); } - _locbld.setLanguageTag(tag); - + localeBuilder.setLanguageTag(tag); return this; } @@ -2279,7 +2329,7 @@ */ public Builder setLanguage(String language) { try { - _locbld.setLanguage(language); + localeBuilder.setLanguage(language); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2300,7 +2350,7 @@ */ public Builder setScript(String script) { try { - _locbld.setScript(script); + localeBuilder.setScript(script); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2325,7 +2375,7 @@ */ public Builder setRegion(String region) { try { - _locbld.setRegion(region); + localeBuilder.setRegion(region); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2352,7 +2402,7 @@ */ public Builder setVariant(String variant) { try { - _locbld.setVariant(variant); + localeBuilder.setVariant(variant); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2384,7 +2434,7 @@ */ public Builder setExtension(char key, String value) { try { - _locbld.setExtension(key, value); + localeBuilder.setExtension(key, value); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2414,7 +2464,7 @@ */ public Builder setUnicodeLocaleKeyword(String key, String type) { try { - _locbld.setUnicodeLocaleKeyword(key, type); + localeBuilder.setUnicodeLocaleKeyword(key, type); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2435,7 +2485,7 @@ */ public Builder addUnicodeLocaleAttribute(String attribute) { try { - _locbld.addUnicodeLocaleAttribute(attribute); + localeBuilder.addUnicodeLocaleAttribute(attribute); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2458,7 +2508,7 @@ */ public Builder removeUnicodeLocaleAttribute(String attribute) { try { - _locbld.removeUnicodeLocaleAttribute(attribute); + localeBuilder.removeUnicodeLocaleAttribute(attribute); } catch (LocaleSyntaxException e) { throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); } @@ -2471,7 +2521,7 @@ * @return This builder. */ public Builder clear() { - _locbld.clear(); + localeBuilder.clear(); return this; } @@ -2483,7 +2533,7 @@ * @see #setExtension(char, String) */ public Builder clearExtensions() { - _locbld.clearExtensions(); + localeBuilder.clearExtensions(); return this; } @@ -2498,9 +2548,9 @@ * @return A Locale. */ public Locale build() { - BaseLocale baseloc = _locbld.getBaseLocale(); - LocaleExtensions extensions = _locbld.getLocaleExtensions(); - if (extensions.isEmpty() && baseloc.getVariant().length() > 0) { + BaseLocale baseloc = localeBuilder.getBaseLocale(); + LocaleExtensions extensions = localeBuilder.getLocaleExtensions(); + if (extensions == null && baseloc.getVariant().length() > 0) { extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(), baseloc.getRegion(), baseloc.getVariant()); } diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/java/util/ResourceBundle.java --- a/jdk/src/share/classes/java/util/ResourceBundle.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/java/util/ResourceBundle.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, 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 @@ -57,7 +57,6 @@ import java.util.jar.JarEntry; import sun.util.locale.BaseLocale; -import sun.util.locale.LocaleExtensions; import sun.util.locale.LocaleObjectCache; @@ -290,7 +289,7 @@ * name for compatibility with some workarounds for bug 4212439. */ private static final ConcurrentMap cacheList - = new ConcurrentHashMap(INITIAL_CACHE_SIZE); + = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE); /** * Queue for reference objects referring to class loaders or bundles. @@ -1755,7 +1754,7 @@ * @since 1.6 */ public Set keySet() { - Set keys = new HashSet(); + Set keys = new HashSet<>(); for (ResourceBundle rb = this; rb != null; rb = rb.parent) { keys.addAll(rb.handleKeySet()); } @@ -1783,7 +1782,7 @@ if (keySet == null) { synchronized (this) { if (keySet == null) { - Set keys = new HashSet(); + Set keys = new HashSet<>(); Enumeration enumKeys = getKeys(); while (enumKeys.hasMoreElements()) { String key = enumKeys.nextElement(); @@ -2301,7 +2300,7 @@ if (baseName == null) { throw new NullPointerException(); } - return new ArrayList(CANDIDATES_CACHE.get(locale.getBaseLocale())); + return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale())); } private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache(); @@ -2327,14 +2326,14 @@ if (language.equals("nb") || isNorwegianBokmal) { List tmpList = getDefaultList("nb", script, region, variant); // Insert a locale replacing "nb" with "no" for every list entry - List bokmalList = new LinkedList(); + List bokmalList = new LinkedList<>(); for (Locale l : tmpList) { bokmalList.add(l); if (l.getLanguage().length() == 0) { break; } bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(), - l.getVariant(), LocaleExtensions.EMPTY_EXTENSIONS)); + l.getVariant(), null)); } return bokmalList; } else if (language.equals("nn") || isNorwegianNynorsk) { @@ -2374,7 +2373,7 @@ List variants = null; if (variant.length() > 0) { - variants = new LinkedList(); + variants = new LinkedList<>(); int idx = variant.length(); while (idx != -1) { variants.add(variant.substring(0, idx)); @@ -2382,32 +2381,32 @@ } } - LinkedList list = new LinkedList(); + List list = new LinkedList<>(); if (variants != null) { for (String v : variants) { - list.add(Locale.getInstance(language, script, region, v, LocaleExtensions.EMPTY_EXTENSIONS)); + list.add(Locale.getInstance(language, script, region, v, null)); } } if (region.length() > 0) { - list.add(Locale.getInstance(language, script, region, "", LocaleExtensions.EMPTY_EXTENSIONS)); + list.add(Locale.getInstance(language, script, region, "", null)); } if (script.length() > 0) { - list.add(Locale.getInstance(language, script, "", "", LocaleExtensions.EMPTY_EXTENSIONS)); + list.add(Locale.getInstance(language, script, "", "", null)); // With script, after truncating variant, region and script, // start over without script. if (variants != null) { for (String v : variants) { - list.add(Locale.getInstance(language, "", region, v, LocaleExtensions.EMPTY_EXTENSIONS)); + list.add(Locale.getInstance(language, "", region, v, null)); } } if (region.length() > 0) { - list.add(Locale.getInstance(language, "", region, "", LocaleExtensions.EMPTY_EXTENSIONS)); + list.add(Locale.getInstance(language, "", region, "", null)); } } if (language.length() > 0) { - list.add(Locale.getInstance(language, "", "", "", LocaleExtensions.EMPTY_EXTENSIONS)); + list.add(Locale.getInstance(language, "", "", "", null)); } // Add root locale at the end list.add(Locale.ROOT); diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/BaseLocale.java --- a/jdk/src/share/classes/sun/util/locale/BaseLocale.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/BaseLocale.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -38,38 +38,46 @@ public static final String SEP = "_"; private static final Cache CACHE = new Cache(); - public static final BaseLocale ROOT = BaseLocale.getInstance("", "", "", ""); + + private final String language; + private final String script; + private final String region; + private final String variant; + + private volatile int hash = 0; - private String _language = ""; - private String _script = ""; - private String _region = ""; - private String _variant = ""; - - private transient volatile int _hash = 0; + // This method must be called only when creating the Locale.* constants. + private BaseLocale(String language, String region) { + this.language = language; + this.script = ""; + this.region = region; + this.variant = ""; + } private BaseLocale(String language, String script, String region, String variant) { - if (language != null) { - _language = AsciiUtil.toLowerString(language).intern(); - } - if (script != null) { - _script = AsciiUtil.toTitleString(script).intern(); - } - if (region != null) { - _region = AsciiUtil.toUpperString(region).intern(); - } - if (variant != null) { - _variant = variant.intern(); - } + this.language = (language != null) ? LocaleUtils.toLowerString(language).intern() : ""; + this.script = (script != null) ? LocaleUtils.toTitleString(script).intern() : ""; + this.region = (region != null) ? LocaleUtils.toUpperString(region).intern() : ""; + this.variant = (variant != null) ? variant.intern() : ""; } - public static BaseLocale getInstance(String language, String script, String region, String variant) { + // Called for creating the Locale.* constants. No argument + // validation is performed. + public static BaseLocale createInstance(String language, String region) { + BaseLocale base = new BaseLocale(language, region); + CACHE.put(new Key(language, region), base); + return base; + } + + public static BaseLocale getInstance(String language, String script, + String region, String variant) { // JDK uses deprecated ISO639.1 language codes for he, yi and id if (language != null) { - if (AsciiUtil.caseIgnoreMatch(language, "he")) { + if (LocaleUtils.caseIgnoreMatch(language, "he")) { language = "iw"; - } else if (AsciiUtil.caseIgnoreMatch(language, "yi")) { + } else if (LocaleUtils.caseIgnoreMatch(language, "yi")) { language = "ji"; - } else if (AsciiUtil.caseIgnoreMatch(language, "id")) { + } else if (LocaleUtils.caseIgnoreMatch(language, "id")) { language = "in"; } } @@ -80,21 +88,22 @@ } public String getLanguage() { - return _language; + return language; } public String getScript() { - return _script; + return script; } public String getRegion() { - return _region; + return region; } public String getVariant() { - return _variant; + return variant; } + @Override public boolean equals(Object obj) { if (this == obj) { return true; @@ -103,138 +112,178 @@ return false; } BaseLocale other = (BaseLocale)obj; - return hashCode() == other.hashCode() - && _language.equals(other._language) - && _script.equals(other._script) - && _region.equals(other._region) - && _variant.equals(other._variant); + return language == other.language + && script == other.script + && region == other.region + && variant == other.variant; } + @Override public String toString() { StringBuilder buf = new StringBuilder(); - if (_language.length() > 0) { + if (language.length() > 0) { buf.append("language="); - buf.append(_language); + buf.append(language); } - if (_script.length() > 0) { + if (script.length() > 0) { if (buf.length() > 0) { buf.append(", "); } buf.append("script="); - buf.append(_script); + buf.append(script); } - if (_region.length() > 0) { + if (region.length() > 0) { if (buf.length() > 0) { buf.append(", "); } buf.append("region="); - buf.append(_region); + buf.append(region); } - if (_variant.length() > 0) { + if (variant.length() > 0) { if (buf.length() > 0) { buf.append(", "); } buf.append("variant="); - buf.append(_variant); + buf.append(variant); } return buf.toString(); } + @Override public int hashCode() { - int h = _hash; + int h = hash; if (h == 0) { // Generating a hash value from language, script, region and variant - for (int i = 0; i < _language.length(); i++) { - h = 31*h + _language.charAt(i); - } - for (int i = 0; i < _script.length(); i++) { - h = 31*h + _script.charAt(i); - } - for (int i = 0; i < _region.length(); i++) { - h = 31*h + _region.charAt(i); - } - for (int i = 0; i < _variant.length(); i++) { - h = 31*h + _variant.charAt(i); - } - _hash = h; + h = language.hashCode(); + h = 31 * h + script.hashCode(); + h = 31 * h + region.hashCode(); + h = 31 * h + variant.hashCode(); + hash = h; } return h; } - private static class Key implements Comparable { - private String _lang = ""; - private String _scrt = ""; - private String _regn = ""; - private String _vart = ""; + private static final class Key implements Comparable { + private final String lang; + private final String scrt; + private final String regn; + private final String vart; + private final boolean normalized; + private final int hash; + + /** + * Creates a Key. language and region must be normalized + * (intern'ed in the proper case). + */ + private Key(String language, String region) { + assert language.intern() == language + && region.intern() == region; - private volatile int _hash; // Default to 0 + lang = language; + scrt = ""; + regn = region; + vart = ""; + this.normalized = true; + + int h = language.hashCode(); + if (region != "") { + int len = region.length(); + for (int i = 0; i < len; i++) { + h = 31 * h + LocaleUtils.toLower(region.charAt(i)); + } + } + hash = h; + } public Key(String language, String script, String region, String variant) { + this(language, script, region, variant, false); + } + + private Key(String language, String script, String region, + String variant, boolean normalized) { + int h = 0; if (language != null) { - _lang = language; + lang = language; + int len = language.length(); + for (int i = 0; i < len; i++) { + h = 31*h + LocaleUtils.toLower(language.charAt(i)); + } + } else { + lang = ""; } if (script != null) { - _scrt = script; + scrt = script; + int len = script.length(); + for (int i = 0; i < len; i++) { + h = 31*h + LocaleUtils.toLower(script.charAt(i)); + } + } else { + scrt = ""; } if (region != null) { - _regn = region; + regn = region; + int len = region.length(); + for (int i = 0; i < len; i++) { + h = 31*h + LocaleUtils.toLower(region.charAt(i)); + } + } else { + regn = ""; } if (variant != null) { - _vart = variant; + vart = variant; + int len = variant.length(); + for (int i = 0; i < len; i++) { + h = 31*h + variant.charAt(i); + } + } else { + vart = ""; } + hash = h; + this.normalized = normalized; } + @Override public boolean equals(Object obj) { return (this == obj) || (obj instanceof Key) - && AsciiUtil.caseIgnoreMatch(((Key)obj)._lang, this._lang) - && AsciiUtil.caseIgnoreMatch(((Key)obj)._scrt, this._scrt) - && AsciiUtil.caseIgnoreMatch(((Key)obj)._regn, this._regn) - && ((Key)obj)._vart.equals(_vart); // variant is case sensitive in JDK! + && this.hash == ((Key)obj).hash + && LocaleUtils.caseIgnoreMatch(((Key)obj).lang, this.lang) + && LocaleUtils.caseIgnoreMatch(((Key)obj).scrt, this.scrt) + && LocaleUtils.caseIgnoreMatch(((Key)obj).regn, this.regn) + && ((Key)obj).vart.equals(vart); // variant is case sensitive in JDK! } + @Override public int compareTo(Key other) { - int res = AsciiUtil.caseIgnoreCompare(this._lang, other._lang); + int res = LocaleUtils.caseIgnoreCompare(this.lang, other.lang); if (res == 0) { - res = AsciiUtil.caseIgnoreCompare(this._scrt, other._scrt); + res = LocaleUtils.caseIgnoreCompare(this.scrt, other.scrt); if (res == 0) { - res = AsciiUtil.caseIgnoreCompare(this._regn, other._regn); + res = LocaleUtils.caseIgnoreCompare(this.regn, other.regn); if (res == 0) { - res = this._vart.compareTo(other._vart); + res = this.vart.compareTo(other.vart); } } } return res; } + @Override public int hashCode() { - int h = _hash; - if (h == 0) { - // Generating a hash value from language, script, region and variant - for (int i = 0; i < _lang.length(); i++) { - h = 31*h + AsciiUtil.toLower(_lang.charAt(i)); - } - for (int i = 0; i < _scrt.length(); i++) { - h = 31*h + AsciiUtil.toLower(_scrt.charAt(i)); - } - for (int i = 0; i < _regn.length(); i++) { - h = 31*h + AsciiUtil.toLower(_regn.charAt(i)); - } - for (int i = 0; i < _vart.length(); i++) { - h = 31*h + _vart.charAt(i); - } - _hash = h; - } - return h; + return hash; } public static Key normalize(Key key) { - String lang = AsciiUtil.toLowerString(key._lang).intern(); - String scrt = AsciiUtil.toTitleString(key._scrt).intern(); - String regn = AsciiUtil.toUpperString(key._regn).intern(); - String vart = key._vart.intern(); // preserve upper/lower cases + if (key.normalized) { + return key; + } - return new Key(lang, scrt, regn, vart); + String lang = LocaleUtils.toLowerString(key.lang).intern(); + String scrt = LocaleUtils.toTitleString(key.scrt).intern(); + String regn = LocaleUtils.toUpperString(key.regn).intern(); + String vart = key.vart.intern(); // preserve upper/lower cases + + return new Key(lang, scrt, regn, vart, true); } } @@ -243,13 +292,14 @@ public Cache() { } + @Override protected Key normalizeKey(Key key) { return Key.normalize(key); } + @Override protected BaseLocale createObject(Key key) { - return new BaseLocale(key._lang, key._scrt, key._regn, key._vart); + return new BaseLocale(key.lang, key.scrt, key.regn, key.vart); } - } } diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/Extension.java --- a/jdk/src/share/classes/sun/util/locale/Extension.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/Extension.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -32,29 +32,34 @@ package sun.util.locale; -public class Extension { - private char _key; - protected String _value; +class Extension { + private final char key; + private String value, id; protected Extension(char key) { - _key = key; + this.key = key; } Extension(char key, String value) { - _key = key; - _value = value; + this.key = key; + setValue(value); + } + + protected void setValue(String value) { + this.value = value; + this.id = key + LanguageTag.SEP + value; } public char getKey() { - return _key; + return key; } public String getValue() { - return _value; + return value; } public String getID() { - return _key + LanguageTag.SEP + _value; + return id; } public String toString() { diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/InternalLocaleBuilder.java --- a/jdk/src/share/classes/sun/util/locale/InternalLocaleBuilder.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/InternalLocaleBuilder.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -35,64 +35,66 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; public final class InternalLocaleBuilder { - private String _language = ""; - private String _script = ""; - private String _region = ""; - private String _variant = ""; + private static final CaseInsensitiveChar PRIVATEUSE_KEY + = new CaseInsensitiveChar(LanguageTag.PRIVATEUSE); - private static final CaseInsensitiveChar PRIVUSE_KEY = new CaseInsensitiveChar(LanguageTag.PRIVATEUSE.charAt(0)); + private String language = ""; + private String script = ""; + private String region = ""; + private String variant = ""; - private HashMap _extensions; - private HashSet _uattributes; - private HashMap _ukeywords; + private Map extensions; + private Set uattributes; + private Map ukeywords; public InternalLocaleBuilder() { } public InternalLocaleBuilder setLanguage(String language) throws LocaleSyntaxException { - if (language == null || language.length() == 0) { - _language = ""; + if (LocaleUtils.isEmpty(language)) { + this.language = ""; } else { if (!LanguageTag.isLanguage(language)) { throw new LocaleSyntaxException("Ill-formed language: " + language, 0); } - _language = language; + this.language = language; } return this; } public InternalLocaleBuilder setScript(String script) throws LocaleSyntaxException { - if (script == null || script.length() == 0) { - _script = ""; + if (LocaleUtils.isEmpty(script)) { + this.script = ""; } else { if (!LanguageTag.isScript(script)) { throw new LocaleSyntaxException("Ill-formed script: " + script, 0); } - _script = script; + this.script = script; } return this; } public InternalLocaleBuilder setRegion(String region) throws LocaleSyntaxException { - if (region == null || region.length() == 0) { - _region = ""; + if (LocaleUtils.isEmpty(region)) { + this.region = ""; } else { if (!LanguageTag.isRegion(region)) { throw new LocaleSyntaxException("Ill-formed region: " + region, 0); } - _region = region; + this.region = region; } return this; } public InternalLocaleBuilder setVariant(String variant) throws LocaleSyntaxException { - if (variant == null || variant.length() == 0) { - _variant = ""; + if (LocaleUtils.isEmpty(variant)) { + this.variant = ""; } else { // normalize separators to "_" String var = variant.replaceAll(LanguageTag.SEP, BaseLocale.SEP); @@ -100,7 +102,7 @@ if (errIdx != -1) { throw new LocaleSyntaxException("Ill-formed variant: " + variant, errIdx); } - _variant = var; + this.variant = var; } return this; } @@ -110,10 +112,10 @@ throw new LocaleSyntaxException("Ill-formed Unicode locale attribute: " + attribute); } // Use case insensitive string to prevent duplication - if (_uattributes == null) { - _uattributes = new HashSet(4); + if (uattributes == null) { + uattributes = new HashSet<>(4); } - _uattributes.add(new CaseInsensitiveString(attribute)); + uattributes.add(new CaseInsensitiveString(attribute)); return this; } @@ -121,8 +123,8 @@ if (attribute == null || !UnicodeLocaleExtension.isAttribute(attribute)) { throw new LocaleSyntaxException("Ill-formed Unicode locale attribute: " + attribute); } - if (_uattributes != null) { - _uattributes.remove(new CaseInsensitiveString(attribute)); + if (uattributes != null) { + uattributes.remove(new CaseInsensitiveString(attribute)); } return this; } @@ -134,9 +136,9 @@ CaseInsensitiveString cikey = new CaseInsensitiveString(key); if (type == null) { - if (_ukeywords != null) { + if (ukeywords != null) { // null type is used for remove the key - _ukeywords.remove(cikey); + ukeywords.remove(cikey); } } else { if (type.length() != 0) { @@ -147,15 +149,17 @@ while (!itr.isDone()) { String s = itr.current(); if (!UnicodeLocaleExtension.isTypeSubtag(s)) { - throw new LocaleSyntaxException("Ill-formed Unicode locale keyword type: " + type, itr.currentStart()); + throw new LocaleSyntaxException("Ill-formed Unicode locale keyword type: " + + type, + itr.currentStart()); } itr.next(); } } - if (_ukeywords == null) { - _ukeywords = new HashMap(4); + if (ukeywords == null) { + ukeywords = new HashMap<>(4); } - _ukeywords.put(cikey, type); + ukeywords.put(cikey, type); } return this; } @@ -167,21 +171,21 @@ throw new LocaleSyntaxException("Ill-formed extension key: " + singleton); } - boolean remove = (value == null || value.length() == 0); + boolean remove = LocaleUtils.isEmpty(value); CaseInsensitiveChar key = new CaseInsensitiveChar(singleton); if (remove) { if (UnicodeLocaleExtension.isSingletonChar(key.value())) { // clear entire Unicode locale extension - if (_uattributes != null) { - _uattributes.clear(); + if (uattributes != null) { + uattributes.clear(); } - if (_ukeywords != null) { - _ukeywords.clear(); + if (ukeywords != null) { + ukeywords.clear(); } } else { - if (_extensions != null && _extensions.containsKey(key)) { - _extensions.remove(key); + if (extensions != null && extensions.containsKey(key)) { + extensions.remove(key); } } } else { @@ -197,7 +201,8 @@ validSubtag = LanguageTag.isExtensionSubtag(s); } if (!validSubtag) { - throw new LocaleSyntaxException("Ill-formed extension value: " + s, itr.currentStart()); + throw new LocaleSyntaxException("Ill-formed extension value: " + s, + itr.currentStart()); } itr.next(); } @@ -205,10 +210,10 @@ if (UnicodeLocaleExtension.isSingletonChar(key.value())) { setUnicodeLocaleExtension(val); } else { - if (_extensions == null) { - _extensions = new HashMap(4); + if (extensions == null) { + extensions = new HashMap<>(4); } - _extensions.put(key, val); + extensions.put(key, val); } } return this; @@ -218,7 +223,7 @@ * Set extension/private subtags in a single string representation */ public InternalLocaleBuilder setExtensions(String subtags) throws LocaleSyntaxException { - if (subtags == null || subtags.length() == 0) { + if (LocaleUtils.isEmpty(subtags)) { clearExtensions(); return this; } @@ -252,11 +257,12 @@ } if (parsed < start) { - throw new LocaleSyntaxException("Incomplete extension '" + singleton + "'", start); + throw new LocaleSyntaxException("Incomplete extension '" + singleton + "'", + start); } if (extensions == null) { - extensions = new ArrayList(4); + extensions = new ArrayList<>(4); } extensions.add(sb.toString()); } else { @@ -281,7 +287,9 @@ itr.next(); } if (parsed <= start) { - throw new LocaleSyntaxException("Incomplete privateuse:" + subtags.substring(start), start); + throw new LocaleSyntaxException("Incomplete privateuse:" + + subtags.substring(start), + start); } else { privateuse = sb.toString(); } @@ -289,7 +297,9 @@ } if (!itr.isDone()) { - throw new LocaleSyntaxException("Ill-formed extension subtags:" + subtags.substring(itr.currentStart()), itr.currentStart()); + throw new LocaleSyntaxException("Ill-formed extension subtags:" + + subtags.substring(itr.currentStart()), + itr.currentStart()); } return setExtensions(extensions, privateuse); @@ -302,30 +312,31 @@ private InternalLocaleBuilder setExtensions(List bcpExtensions, String privateuse) { clearExtensions(); - if (bcpExtensions != null && bcpExtensions.size() > 0) { - HashSet processedExntensions = new HashSet(bcpExtensions.size()); + if (!LocaleUtils.isEmpty(bcpExtensions)) { + Set done = new HashSet<>(bcpExtensions.size()); for (String bcpExt : bcpExtensions) { - CaseInsensitiveChar key = new CaseInsensitiveChar(bcpExt.charAt(0)); + CaseInsensitiveChar key = new CaseInsensitiveChar(bcpExt); // ignore duplicates - if (!processedExntensions.contains(key)) { + if (!done.contains(key)) { // each extension string contains singleton, e.g. "a-abc-def" if (UnicodeLocaleExtension.isSingletonChar(key.value())) { setUnicodeLocaleExtension(bcpExt.substring(2)); } else { - if (_extensions == null) { - _extensions = new HashMap(4); + if (extensions == null) { + extensions = new HashMap<>(4); } - _extensions.put(key, bcpExt.substring(2)); + extensions.put(key, bcpExt.substring(2)); } } + done.add(key); } } if (privateuse != null && privateuse.length() > 0) { // privateuse string contains prefix, e.g. "x-abc-def" - if (_extensions == null) { - _extensions = new HashMap(1); + if (extensions == null) { + extensions = new HashMap<>(1); } - _extensions.put(new CaseInsensitiveChar(privateuse.charAt(0)), privateuse.substring(2)); + extensions.put(new CaseInsensitiveChar(privateuse), privateuse.substring(2)); } return this; @@ -336,24 +347,25 @@ */ public InternalLocaleBuilder setLanguageTag(LanguageTag langtag) { clear(); - if (langtag.getExtlangs().size() > 0) { - _language = langtag.getExtlangs().get(0); + if (!langtag.getExtlangs().isEmpty()) { + language = langtag.getExtlangs().get(0); } else { - String language = langtag.getLanguage(); - if (!language.equals(LanguageTag.UNDETERMINED)) { - _language = language; + String lang = langtag.getLanguage(); + if (!lang.equals(LanguageTag.UNDETERMINED)) { + language = lang; } } - _script = langtag.getScript(); - _region = langtag.getRegion(); + script = langtag.getScript(); + region = langtag.getRegion(); List bcpVariants = langtag.getVariants(); - if (bcpVariants.size() > 0) { + if (!bcpVariants.isEmpty()) { StringBuilder var = new StringBuilder(bcpVariants.get(0)); - for (int i = 1; i < bcpVariants.size(); i++) { + int size = bcpVariants.size(); + for (int i = 1; i < size; i++) { var.append(BaseLocale.SEP).append(bcpVariants.get(i)); } - _variant = var.toString(); + variant = var.toString(); } setExtensions(langtag.getExtensions(), langtag.getPrivateuse()); @@ -361,7 +373,7 @@ return this; } - public InternalLocaleBuilder setLocale(BaseLocale base, LocaleExtensions extensions) throws LocaleSyntaxException { + public InternalLocaleBuilder setLocale(BaseLocale base, LocaleExtensions localeExtensions) throws LocaleSyntaxException { String language = base.getLanguage(); String script = base.getScript(); String region = base.getRegion(); @@ -373,14 +385,14 @@ if (language.equals("ja") && region.equals("JP") && variant.equals("JP")) { // When locale ja_JP_JP is created, ca-japanese is always there. // The builder ignores the variant "JP" - assert("japanese".equals(extensions.getUnicodeLocaleType("ca"))); + assert("japanese".equals(localeExtensions.getUnicodeLocaleType("ca"))); variant = ""; } // Exception 2 - th_TH_TH else if (language.equals("th") && region.equals("TH") && variant.equals("TH")) { // When locale th_TH_TH is created, nu-thai is always there. // The builder ignores the variant "TH" - assert("thai".equals(extensions.getUnicodeLocaleType("nu"))); + assert("thai".equals(localeExtensions.getUnicodeLocaleType("nu"))); variant = ""; } // Exception 3 - no_NO_NY @@ -415,36 +427,36 @@ // The input locale is validated at this point. // Now, updating builder's internal fields. - _language = language; - _script = script; - _region = region; - _variant = variant; + this.language = language; + this.script = script; + this.region = region; + this.variant = variant; clearExtensions(); - Set extKeys = (extensions == null) ? null : extensions.getKeys(); + Set extKeys = (localeExtensions == null) ? null : localeExtensions.getKeys(); if (extKeys != null) { - // map extensions back to builder's internal format + // map localeExtensions back to builder's internal format for (Character key : extKeys) { - Extension e = extensions.getExtension(key); + Extension e = localeExtensions.getExtension(key); if (e instanceof UnicodeLocaleExtension) { UnicodeLocaleExtension ue = (UnicodeLocaleExtension)e; for (String uatr : ue.getUnicodeLocaleAttributes()) { - if (_uattributes == null) { - _uattributes = new HashSet(4); + if (uattributes == null) { + uattributes = new HashSet<>(4); } - _uattributes.add(new CaseInsensitiveString(uatr)); + uattributes.add(new CaseInsensitiveString(uatr)); } for (String ukey : ue.getUnicodeLocaleKeys()) { - if (_ukeywords == null) { - _ukeywords = new HashMap(4); + if (ukeywords == null) { + ukeywords = new HashMap<>(4); } - _ukeywords.put(new CaseInsensitiveString(ukey), ue.getUnicodeLocaleType(ukey)); + ukeywords.put(new CaseInsensitiveString(ukey), ue.getUnicodeLocaleType(ukey)); } } else { - if (_extensions == null) { - _extensions = new HashMap(4); + if (extensions == null) { + extensions = new HashMap<>(4); } - _extensions.put(new CaseInsensitiveChar(key.charValue()), e.getValue()); + extensions.put(new CaseInsensitiveChar(key), e.getValue()); } } } @@ -452,37 +464,37 @@ } public InternalLocaleBuilder clear() { - _language = ""; - _script = ""; - _region = ""; - _variant = ""; + language = ""; + script = ""; + region = ""; + variant = ""; clearExtensions(); return this; } public InternalLocaleBuilder clearExtensions() { - if (_extensions != null) { - _extensions.clear(); + if (extensions != null) { + extensions.clear(); } - if (_uattributes != null) { - _uattributes.clear(); + if (uattributes != null) { + uattributes.clear(); } - if (_ukeywords != null) { - _ukeywords.clear(); + if (ukeywords != null) { + ukeywords.clear(); } return this; } public BaseLocale getBaseLocale() { - String language = _language; - String script = _script; - String region = _region; - String variant = _variant; + String language = this.language; + String script = this.script; + String region = this.region; + String variant = this.variant; // Special private use subtag sequence identified by "lvariant" will be // interpreted as Java variant. - if (_extensions != null) { - String privuse = _extensions.get(PRIVUSE_KEY); + if (extensions != null) { + String privuse = extensions.get(PRIVATEUSE_KEY); if (privuse != null) { StringTokenIterator itr = new StringTokenIterator(privuse, LanguageTag.SEP); boolean sawPrefix = false; @@ -492,7 +504,7 @@ privVarStart = itr.currentStart(); break; } - if (AsciiUtil.caseIgnoreMatch(itr.current(), LanguageTag.PRIVUSE_VARIANT_PREFIX)) { + if (LocaleUtils.caseIgnoreMatch(itr.current(), LanguageTag.PRIVUSE_VARIANT_PREFIX)) { sawPrefix = true; } itr.next(); @@ -502,7 +514,8 @@ if (sb.length() != 0) { sb.append(BaseLocale.SEP); } - sb.append(privuse.substring(privVarStart).replaceAll(LanguageTag.SEP, BaseLocale.SEP)); + sb.append(privuse.substring(privVarStart).replaceAll(LanguageTag.SEP, + BaseLocale.SEP)); variant = sb.toString(); } } @@ -512,13 +525,13 @@ } public LocaleExtensions getLocaleExtensions() { - if ((_extensions == null || _extensions.size() == 0) - && (_uattributes == null || _uattributes.size() == 0) - && (_ukeywords == null || _ukeywords.size() == 0)) { - return LocaleExtensions.EMPTY_EXTENSIONS; + if (LocaleUtils.isEmpty(extensions) && LocaleUtils.isEmpty(uattributes) + && LocaleUtils.isEmpty(ukeywords)) { + return null; } - return new LocaleExtensions(_extensions, _uattributes, _ukeywords); + LocaleExtensions lext = new LocaleExtensions(extensions, uattributes, ukeywords); + return lext.isEmpty() ? null : lext; } /* @@ -540,7 +553,7 @@ sawPrivuseVar = true; break; } - if (AsciiUtil.caseIgnoreMatch(itr.current(), LanguageTag.PRIVUSE_VARIANT_PREFIX)) { + if (LocaleUtils.caseIgnoreMatch(itr.current(), LanguageTag.PRIVUSE_VARIANT_PREFIX)) { prefixStart = itr.currentStart(); } itr.next(); @@ -576,11 +589,11 @@ */ private void setUnicodeLocaleExtension(String subtags) { // wipe out existing attributes/keywords - if (_uattributes != null) { - _uattributes.clear(); + if (uattributes != null) { + uattributes.clear(); } - if (_ukeywords != null) { - _ukeywords.clear(); + if (ukeywords != null) { + ukeywords.clear(); } StringTokenIterator itr = new StringTokenIterator(subtags, LanguageTag.SEP); @@ -590,10 +603,10 @@ if (!UnicodeLocaleExtension.isAttribute(itr.current())) { break; } - if (_uattributes == null) { - _uattributes = new HashSet(4); + if (uattributes == null) { + uattributes = new HashSet<>(4); } - _uattributes.add(new CaseInsensitiveString(itr.current())); + uattributes.add(new CaseInsensitiveString(itr.current())); itr.next(); } @@ -608,14 +621,14 @@ // next keyword - emit previous one assert(typeStart == -1 || typeEnd != -1); type = (typeStart == -1) ? "" : subtags.substring(typeStart, typeEnd); - if (_ukeywords == null) { - _ukeywords = new HashMap(4); + if (ukeywords == null) { + ukeywords = new HashMap<>(4); } - _ukeywords.put(key, type); + ukeywords.put(key, type); // reset keyword info CaseInsensitiveString tmpKey = new CaseInsensitiveString(itr.current()); - key = _ukeywords.containsKey(tmpKey) ? null : tmpKey; + key = ukeywords.containsKey(tmpKey) ? null : tmpKey; typeStart = typeEnd = -1; } else { if (typeStart == -1) { @@ -627,7 +640,7 @@ // 1. first keyword or // 2. next keyword, but previous one was duplicate key = new CaseInsensitiveString(itr.current()); - if (_ukeywords != null && _ukeywords.containsKey(key)) { + if (ukeywords != null && ukeywords.containsKey(key)) { // duplicate key = null; } @@ -638,10 +651,10 @@ // last keyword assert(typeStart == -1 || typeEnd != -1); type = (typeStart == -1) ? "" : subtags.substring(typeStart, typeEnd); - if (_ukeywords == null) { - _ukeywords = new HashMap(4); + if (ukeywords == null) { + ukeywords = new HashMap<>(4); } - _ukeywords.put(key, type); + ukeywords.put(key, type); } break; } @@ -650,21 +663,24 @@ } } - static class CaseInsensitiveString { - private String _s; + static final class CaseInsensitiveString { + private final String str, lowerStr; CaseInsensitiveString(String s) { - _s = s; + str = s; + lowerStr = LocaleUtils.toLowerString(s); } public String value() { - return _s; + return str; } + @Override public int hashCode() { - return AsciiUtil.toLowerString(_s).hashCode(); + return lowerStr.hashCode(); } + @Override public boolean equals(Object obj) { if (this == obj) { return true; @@ -672,25 +688,36 @@ if (!(obj instanceof CaseInsensitiveString)) { return false; } - return AsciiUtil.caseIgnoreMatch(_s, ((CaseInsensitiveString)obj).value()); + return lowerStr.equals(((CaseInsensitiveString)obj).lowerStr); } } - static class CaseInsensitiveChar { - private char _c; + static final class CaseInsensitiveChar { + private final char ch, lowerCh; + + /** + * Constructs a CaseInsensitiveChar with the first char of the + * given s. + */ + private CaseInsensitiveChar(String s) { + this(s.charAt(0)); + } CaseInsensitiveChar(char c) { - _c = c; + ch = c; + lowerCh = LocaleUtils.toLower(ch); } public char value() { - return _c; + return ch; } + @Override public int hashCode() { - return AsciiUtil.toLower(_c); + return lowerCh; } + @Override public boolean equals(Object obj) { if (this == obj) { return true; @@ -698,8 +725,7 @@ if (!(obj instanceof CaseInsensitiveChar)) { return false; } - return _c == AsciiUtil.toLower(((CaseInsensitiveChar)obj).value()); + return lowerCh == ((CaseInsensitiveChar)obj).lowerCh; } - } } diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/LanguageTag.java --- a/jdk/src/share/classes/sun/util/locale/LanguageTag.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/LanguageTag.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -44,25 +44,25 @@ // public static final String SEP = "-"; public static final String PRIVATEUSE = "x"; - public static String UNDETERMINED = "und"; + public static final String UNDETERMINED = "und"; public static final String PRIVUSE_VARIANT_PREFIX = "lvariant"; // // Language subtag fields // - private String _language = ""; // language subtag - private String _script = ""; // script subtag - private String _region = ""; // region subtag - private String _privateuse = ""; // privateuse + private String language = ""; // language subtag + private String script = ""; // script subtag + private String region = ""; // region subtag + private String privateuse = ""; // privateuse - private List _extlangs = Collections.emptyList(); // extlang subtags - private List _variants = Collections.emptyList(); // variant subtags - private List _extensions = Collections.emptyList(); // extensions + private List extlangs = Collections.emptyList(); // extlang subtags + private List variants = Collections.emptyList(); // variant subtags + private List extensions = Collections.emptyList(); // extensions // Map contains grandfathered tags and its preferred mappings from // http://www.ietf.org/rfc/rfc5646.txt - private static final Map GRANDFATHERED = - new HashMap(); + // Keys are lower-case strings. + private static final Map GRANDFATHERED = new HashMap<>(); static { // grandfathered = irregular ; non-redundant tags registered @@ -126,7 +126,7 @@ {"zh-xiang", "hsn"}, }; for (String[] e : entries) { - GRANDFATHERED.put(new AsciiUtil.CaseInsensitiveKey(e[0]), e); + GRANDFATHERED.put(LocaleUtils.toLowerString(e[0]), e); } } @@ -188,7 +188,7 @@ StringTokenIterator itr; // Check if the tag is grandfathered - String[] gfmap = GRANDFATHERED.get(new AsciiUtil.CaseInsensitiveKey(languageTag)); + String[] gfmap = GRANDFATHERED.get(LocaleUtils.toLowerString(languageTag)); if (gfmap != null) { // use preferred mapping itr = new StringTokenIterator(gfmap[1], SEP); @@ -210,11 +210,11 @@ if (!itr.isDone() && !sts.isError()) { String s = itr.current(); - sts._errorIndex = itr.currentStart(); + sts.errorIndex = itr.currentStart(); if (s.length() == 0) { - sts._errorMsg = "Empty subtag"; + sts.errorMsg = "Empty subtag"; } else { - sts._errorMsg = "Invalid subtag: " + s; + sts.errorMsg = "Invalid subtag: " + s; } } @@ -235,8 +235,8 @@ String s = itr.current(); if (isLanguage(s)) { found = true; - _language = s; - sts._parseLength = itr.currentEnd(); + language = s; + sts.parseLength = itr.currentEnd(); itr.next(); } @@ -256,14 +256,14 @@ break; } found = true; - if (_extlangs.isEmpty()) { - _extlangs = new ArrayList(3); + if (extlangs.isEmpty()) { + extlangs = new ArrayList<>(3); } - _extlangs.add(s); - sts._parseLength = itr.currentEnd(); + extlangs.add(s); + sts.parseLength = itr.currentEnd(); itr.next(); - if (_extlangs.size() == 3) { + if (extlangs.size() == 3) { // Maximum 3 extlangs break; } @@ -282,8 +282,8 @@ String s = itr.current(); if (isScript(s)) { found = true; - _script = s; - sts._parseLength = itr.currentEnd(); + script = s; + sts.parseLength = itr.currentEnd(); itr.next(); } @@ -300,8 +300,8 @@ String s = itr.current(); if (isRegion(s)) { found = true; - _region = s; - sts._parseLength = itr.currentEnd(); + region = s; + sts.parseLength = itr.currentEnd(); itr.next(); } @@ -321,11 +321,11 @@ break; } found = true; - if (_variants.isEmpty()) { - _variants = new ArrayList(3); + if (variants.isEmpty()) { + variants = new ArrayList<>(3); } - _variants.add(s); - sts._parseLength = itr.currentEnd(); + variants.add(s); + sts.parseLength = itr.currentEnd(); itr.next(); } @@ -351,23 +351,23 @@ s = itr.current(); if (isExtensionSubtag(s)) { sb.append(SEP).append(s); - sts._parseLength = itr.currentEnd(); + sts.parseLength = itr.currentEnd(); } else { break; } itr.next(); } - if (sts._parseLength <= start) { - sts._errorIndex = start; - sts._errorMsg = "Incomplete extension '" + singleton + "'"; + if (sts.parseLength <= start) { + sts.errorIndex = start; + sts.errorMsg = "Incomplete extension '" + singleton + "'"; break; } - if (_extensions.size() == 0) { - _extensions = new ArrayList(4); + if (extensions.isEmpty()) { + extensions = new ArrayList<>(4); } - _extensions.add(sb.toString()); + extensions.add(sb.toString()); found = true; } else { break; @@ -395,17 +395,17 @@ break; } sb.append(SEP).append(s); - sts._parseLength = itr.currentEnd(); + sts.parseLength = itr.currentEnd(); itr.next(); } - if (sts._parseLength <= start) { + if (sts.parseLength <= start) { // need at least 1 private subtag - sts._errorIndex = start; - sts._errorMsg = "Incomplete privateuse"; + sts.errorIndex = start; + sts.errorMsg = "Incomplete privateuse"; } else { - _privateuse = sb.toString(); + privateuse = sb.toString(); found = true; } } @@ -425,9 +425,8 @@ String privuseVar = null; // store ill-formed variant subtags - if (language.length() > 0 && isLanguage(language)) { - // Convert a deprecated language code used by Java to - // a new code + if (isLanguage(language)) { + // Convert a deprecated language code to its new code if (language.equals("iw")) { language = "he"; } else if (language.equals("ji")) { @@ -435,22 +434,22 @@ } else if (language.equals("in")) { language = "id"; } - tag._language = language; + tag.language = language; } - if (script.length() > 0 && isScript(script)) { - tag._script = canonicalizeScript(script); + if (isScript(script)) { + tag.script = canonicalizeScript(script); hasSubtag = true; } - if (region.length() > 0 && isRegion(region)) { - tag._region = canonicalizeRegion(region); + if (isRegion(region)) { + tag.region = canonicalizeRegion(region); hasSubtag = true; } // Special handling for no_NO_NY - use nn_NO for language tag - if (tag._language.equals("no") && tag._region.equals("NO") && variant.equals("NY")) { - tag._language = "nn"; + if (tag.language.equals("no") && tag.region.equals("NO") && variant.equals("NY")) { + tag.language = "nn"; variant = ""; } @@ -463,13 +462,13 @@ break; } if (variants == null) { - variants = new ArrayList(); + variants = new ArrayList<>(); } variants.add(var); // Do not canonicalize! varitr.next(); } if (variants != null) { - tag._variants = variants; + tag.variants = variants; hasSubtag = true; } if (!varitr.isDone()) { @@ -496,21 +495,23 @@ List extensions = null; String privateuse = null; - Set locextKeys = localeExtensions.getKeys(); - for (Character locextKey : locextKeys) { - Extension ext = localeExtensions.getExtension(locextKey); - if (isPrivateusePrefixChar(locextKey.charValue())) { - privateuse = ext.getValue(); - } else { - if (extensions == null) { - extensions = new ArrayList(); + if (localeExtensions != null) { + Set locextKeys = localeExtensions.getKeys(); + for (Character locextKey : locextKeys) { + Extension ext = localeExtensions.getExtension(locextKey); + if (isPrivateusePrefixChar(locextKey)) { + privateuse = ext.getValue(); + } else { + if (extensions == null) { + extensions = new ArrayList<>(); + } + extensions.add(locextKey.toString() + SEP + ext.getValue()); } - extensions.add(locextKey.toString() + SEP + ext.getValue()); } } if (extensions != null) { - tag._extensions = extensions; + tag.extensions = extensions; hasSubtag = true; } @@ -519,19 +520,20 @@ if (privateuse == null) { privateuse = PRIVUSE_VARIANT_PREFIX + SEP + privuseVar; } else { - privateuse = privateuse + SEP + PRIVUSE_VARIANT_PREFIX + SEP + privuseVar.replace(BaseLocale.SEP, SEP); + privateuse = privateuse + SEP + PRIVUSE_VARIANT_PREFIX + + SEP + privuseVar.replace(BaseLocale.SEP, SEP); } } if (privateuse != null) { - tag._privateuse = privateuse; + tag.privateuse = privateuse; } - if (tag._language.length() == 0 && (hasSubtag || privateuse == null)) { + if (tag.language.length() == 0 && (hasSubtag || privateuse == null)) { // use lang "und" when 1) no language is available AND // 2) any of other subtags other than private use are available or // no private use tag is available - tag._language = UNDETERMINED; + tag.language = UNDETERMINED; } return tag; @@ -542,31 +544,40 @@ // public String getLanguage() { - return _language; + return language; } public List getExtlangs() { - return Collections.unmodifiableList(_extlangs); + if (extlangs.isEmpty()) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(extlangs); } public String getScript() { - return _script; + return script; } public String getRegion() { - return _region; + return region; } public List getVariants() { - return Collections.unmodifiableList(_variants); + if (variants.isEmpty()) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(variants); } public List getExtensions() { - return Collections.unmodifiableList(_extensions); + if (extensions.isEmpty()) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(extensions); } public String getPrivateuse() { - return _privateuse; + return privateuse; } // @@ -579,25 +590,26 @@ // ; extended language subtags // / 4ALPHA ; or reserved for future use // / 5*8ALPHA ; or registered language subtag - return (s.length() >= 2) && (s.length() <= 8) && AsciiUtil.isAlphaString(s); + int len = s.length(); + return (len >= 2) && (len <= 8) && LocaleUtils.isAlphaString(s); } public static boolean isExtlang(String s) { // extlang = 3ALPHA ; selected ISO 639 codes // *2("-" 3ALPHA) ; permanently reserved - return (s.length() == 3) && AsciiUtil.isAlphaString(s); + return (s.length() == 3) && LocaleUtils.isAlphaString(s); } public static boolean isScript(String s) { // script = 4ALPHA ; ISO 15924 code - return (s.length() == 4) && AsciiUtil.isAlphaString(s); + return (s.length() == 4) && LocaleUtils.isAlphaString(s); } public static boolean isRegion(String s) { // region = 2ALPHA ; ISO 3166-1 code // / 3DIGIT ; UN M.49 code - return ((s.length() == 2) && AsciiUtil.isAlphaString(s)) - || ((s.length() == 3) && AsciiUtil.isNumericString(s)); + return ((s.length() == 2) && LocaleUtils.isAlphaString(s)) + || ((s.length() == 3) && LocaleUtils.isNumericString(s)); } public static boolean isVariant(String s) { @@ -605,13 +617,13 @@ // / (DIGIT 3alphanum) int len = s.length(); if (len >= 5 && len <= 8) { - return AsciiUtil.isAlphaNumericString(s); + return LocaleUtils.isAlphaNumericString(s); } if (len == 4) { - return AsciiUtil.isNumeric(s.charAt(0)) - && AsciiUtil.isAlphaNumeric(s.charAt(1)) - && AsciiUtil.isAlphaNumeric(s.charAt(2)) - && AsciiUtil.isAlphaNumeric(s.charAt(3)); + return LocaleUtils.isNumeric(s.charAt(0)) + && LocaleUtils.isAlphaNumeric(s.charAt(1)) + && LocaleUtils.isAlphaNumeric(s.charAt(2)) + && LocaleUtils.isAlphaNumeric(s.charAt(3)); } return false; } @@ -624,8 +636,8 @@ // / %x79-7A ; y - z return (s.length() == 1) - && AsciiUtil.isAlphaString(s) - && !AsciiUtil.caseIgnoreMatch(PRIVATEUSE, s); + && LocaleUtils.isAlphaString(s) + && !LocaleUtils.caseIgnoreMatch(PRIVATEUSE, s); } public static boolean isExtensionSingletonChar(char c) { @@ -634,22 +646,24 @@ public static boolean isExtensionSubtag(String s) { // extension = singleton 1*("-" (2*8alphanum)) - return (s.length() >= 2) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s); + int len = s.length(); + return (len >= 2) && (len <= 8) && LocaleUtils.isAlphaNumericString(s); } public static boolean isPrivateusePrefix(String s) { // privateuse = "x" 1*("-" (1*8alphanum)) return (s.length() == 1) - && AsciiUtil.caseIgnoreMatch(PRIVATEUSE, s); + && LocaleUtils.caseIgnoreMatch(PRIVATEUSE, s); } public static boolean isPrivateusePrefixChar(char c) { - return (AsciiUtil.caseIgnoreMatch(PRIVATEUSE, String.valueOf(c))); + return (LocaleUtils.caseIgnoreMatch(PRIVATEUSE, String.valueOf(c))); } public static boolean isPrivateuseSubtag(String s) { // privateuse = "x" 1*("-" (1*8alphanum)) - return (s.length() >= 1) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s); + int len = s.length(); + return (len >= 1) && (len <= 8) && LocaleUtils.isAlphaNumericString(s); } // @@ -657,76 +671,77 @@ // public static String canonicalizeLanguage(String s) { - return AsciiUtil.toLowerString(s); + return LocaleUtils.toLowerString(s); } public static String canonicalizeExtlang(String s) { - return AsciiUtil.toLowerString(s); + return LocaleUtils.toLowerString(s); } public static String canonicalizeScript(String s) { - return AsciiUtil.toTitleString(s); + return LocaleUtils.toTitleString(s); } public static String canonicalizeRegion(String s) { - return AsciiUtil.toUpperString(s); + return LocaleUtils.toUpperString(s); } public static String canonicalizeVariant(String s) { - return AsciiUtil.toLowerString(s); + return LocaleUtils.toLowerString(s); } public static String canonicalizeExtension(String s) { - return AsciiUtil.toLowerString(s); + return LocaleUtils.toLowerString(s); } public static String canonicalizeExtensionSingleton(String s) { - return AsciiUtil.toLowerString(s); + return LocaleUtils.toLowerString(s); } public static String canonicalizeExtensionSubtag(String s) { - return AsciiUtil.toLowerString(s); + return LocaleUtils.toLowerString(s); } public static String canonicalizePrivateuse(String s) { - return AsciiUtil.toLowerString(s); + return LocaleUtils.toLowerString(s); } public static String canonicalizePrivateuseSubtag(String s) { - return AsciiUtil.toLowerString(s); + return LocaleUtils.toLowerString(s); } + @Override public String toString() { StringBuilder sb = new StringBuilder(); - if (_language.length() > 0) { - sb.append(_language); + if (language.length() > 0) { + sb.append(language); - for (String extlang : _extlangs) { + for (String extlang : extlangs) { sb.append(SEP).append(extlang); } - if (_script.length() > 0) { - sb.append(SEP).append(_script); + if (script.length() > 0) { + sb.append(SEP).append(script); } - if (_region.length() > 0) { - sb.append(SEP).append(_region); + if (region.length() > 0) { + sb.append(SEP).append(region); } - for (String variant : _extlangs) { + for (String variant : variants) { sb.append(SEP).append(variant); } - for (String extension : _extensions) { + for (String extension : extensions) { sb.append(SEP).append(extension); } } - if (_privateuse.length() > 0) { + if (privateuse.length() > 0) { if (sb.length() > 0) { sb.append(SEP); } - sb.append(_privateuse); + sb.append(privateuse); } return sb.toString(); diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/LocaleExtensions.java --- a/jdk/src/share/classes/sun/util/locale/LocaleExtensions.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/LocaleExtensions.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -36,6 +36,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; +import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; @@ -45,55 +46,45 @@ public class LocaleExtensions { - private SortedMap _map; - private String _id; + private final Map extensionMap; + private final String id; - private static final SortedMap EMPTY_MAP = - Collections.unmodifiableSortedMap(new TreeMap()); - - public static final LocaleExtensions EMPTY_EXTENSIONS; - public static final LocaleExtensions CALENDAR_JAPANESE; - public static final LocaleExtensions NUMBER_THAI; + public static final LocaleExtensions CALENDAR_JAPANESE + = new LocaleExtensions("u-ca-japanese", + UnicodeLocaleExtension.SINGLETON, + UnicodeLocaleExtension.CA_JAPANESE); - static { - EMPTY_EXTENSIONS = new LocaleExtensions(); - EMPTY_EXTENSIONS._id = ""; - EMPTY_EXTENSIONS._map = EMPTY_MAP; + public static final LocaleExtensions NUMBER_THAI + = new LocaleExtensions("u-nu-thai", + UnicodeLocaleExtension.SINGLETON, + UnicodeLocaleExtension.NU_THAI); - CALENDAR_JAPANESE = new LocaleExtensions(); - CALENDAR_JAPANESE._id = "u-ca-japanese"; - CALENDAR_JAPANESE._map = new TreeMap(); - CALENDAR_JAPANESE._map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), UnicodeLocaleExtension.CA_JAPANESE); - - NUMBER_THAI = new LocaleExtensions(); - NUMBER_THAI._id = "u-nu-thai"; - NUMBER_THAI._map = new TreeMap(); - NUMBER_THAI._map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), UnicodeLocaleExtension.NU_THAI); - } - - private LocaleExtensions() { + private LocaleExtensions(String id, Character key, Extension value) { + this.id = id; + this.extensionMap = Collections.singletonMap(key, value); } /* - * Package local constructor, only used by InternalLocaleBuilder. + * Package private constructor, only used by InternalLocaleBuilder. */ LocaleExtensions(Map extensions, - Set uattributes, Map ukeywords) { - boolean hasExtension = (extensions != null && extensions.size() > 0); - boolean hasUAttributes = (uattributes != null && uattributes.size() > 0); - boolean hasUKeywords = (ukeywords != null && ukeywords.size() > 0); + Set uattributes, + Map ukeywords) { + boolean hasExtension = !LocaleUtils.isEmpty(extensions); + boolean hasUAttributes = !LocaleUtils.isEmpty(uattributes); + boolean hasUKeywords = !LocaleUtils.isEmpty(ukeywords); if (!hasExtension && !hasUAttributes && !hasUKeywords) { - _map = EMPTY_MAP; - _id = ""; + id = ""; + extensionMap = Collections.emptyMap(); return; } // Build extension map - _map = new TreeMap(); + SortedMap map = new TreeMap<>(); if (hasExtension) { for (Entry ext : extensions.entrySet()) { - char key = AsciiUtil.toLower(ext.getKey().value()); + char key = LocaleUtils.toLower(ext.getKey().value()); String value = ext.getValue(); if (LanguageTag.isPrivateusePrefixChar(key)) { @@ -104,54 +95,57 @@ } } - Extension e = new Extension(key, AsciiUtil.toLowerString(value)); - _map.put(Character.valueOf(key), e); + map.put(key, new Extension(key, LocaleUtils.toLowerString(value))); } } if (hasUAttributes || hasUKeywords) { - TreeSet uaset = null; - TreeMap ukmap = null; + SortedSet uaset = null; + SortedMap ukmap = null; if (hasUAttributes) { - uaset = new TreeSet(); + uaset = new TreeSet<>(); for (CaseInsensitiveString cis : uattributes) { - uaset.add(AsciiUtil.toLowerString(cis.value())); + uaset.add(LocaleUtils.toLowerString(cis.value())); } } if (hasUKeywords) { - ukmap = new TreeMap(); + ukmap = new TreeMap<>(); for (Entry kwd : ukeywords.entrySet()) { - String key = AsciiUtil.toLowerString(kwd.getKey().value()); - String type = AsciiUtil.toLowerString(kwd.getValue()); + String key = LocaleUtils.toLowerString(kwd.getKey().value()); + String type = LocaleUtils.toLowerString(kwd.getValue()); ukmap.put(key, type); } } UnicodeLocaleExtension ule = new UnicodeLocaleExtension(uaset, ukmap); - _map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), ule); + map.put(UnicodeLocaleExtension.SINGLETON, ule); } - if (_map.size() == 0) { + if (map.isEmpty()) { // this could happen when only privuateuse with special variant - _map = EMPTY_MAP; - _id = ""; + id = ""; + extensionMap = Collections.emptyMap(); } else { - _id = toID(_map); + id = toID(map); + extensionMap = map; } } public Set getKeys() { - return Collections.unmodifiableSet(_map.keySet()); + if (extensionMap.isEmpty()) { + return Collections.emptySet(); + } + return Collections.unmodifiableSet(extensionMap.keySet()); } public Extension getExtension(Character key) { - return _map.get(Character.valueOf(AsciiUtil.toLower(key.charValue()))); + return extensionMap.get(LocaleUtils.toLower(key)); } public String getExtensionValue(Character key) { - Extension ext = _map.get(Character.valueOf(AsciiUtil.toLower(key.charValue()))); + Extension ext = extensionMap.get(LocaleUtils.toLower(key)); if (ext == null) { return null; } @@ -159,7 +153,7 @@ } public Set getUnicodeLocaleAttributes() { - Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); + Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON); if (ext == null) { return Collections.emptySet(); } @@ -168,7 +162,7 @@ } public Set getUnicodeLocaleKeys() { - Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); + Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON); if (ext == null) { return Collections.emptySet(); } @@ -177,16 +171,16 @@ } public String getUnicodeLocaleType(String unicodeLocaleKey) { - Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); + Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON); if (ext == null) { return null; } assert (ext instanceof UnicodeLocaleExtension); - return ((UnicodeLocaleExtension)ext).getUnicodeLocaleType(AsciiUtil.toLowerString(unicodeLocaleKey)); + return ((UnicodeLocaleExtension)ext).getUnicodeLocaleType(LocaleUtils.toLowerString(unicodeLocaleKey)); } public boolean isEmpty() { - return _map.isEmpty(); + return extensionMap.isEmpty(); } public static boolean isValidKey(char c) { @@ -201,7 +195,7 @@ StringBuilder buf = new StringBuilder(); Extension privuse = null; for (Entry entry : map.entrySet()) { - char singleton = entry.getKey().charValue(); + char singleton = entry.getKey(); Extension extension = entry.getValue(); if (LanguageTag.isPrivateusePrefixChar(singleton)) { privuse = extension; @@ -221,19 +215,21 @@ return buf.toString(); } - + @Override public String toString() { - return _id; + return id; } public String getID() { - return _id; + return id; } + @Override public int hashCode() { - return _id.hashCode(); + return id.hashCode(); } + @Override public boolean equals(Object other) { if (this == other) { return true; @@ -241,6 +237,6 @@ if (!(other instanceof LocaleExtensions)) { return false; } - return this._id.equals(((LocaleExtensions)other)._id); + return id.equals(((LocaleExtensions)other).id); } } diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/LocaleObjectCache.java --- a/jdk/src/share/classes/sun/util/locale/LocaleObjectCache.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/LocaleObjectCache.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -34,24 +34,25 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; public abstract class LocaleObjectCache { - private ConcurrentHashMap> _map; - private ReferenceQueue _queue = new ReferenceQueue(); + private ConcurrentMap> map; + private ReferenceQueue queue = new ReferenceQueue<>(); public LocaleObjectCache() { this(16, 0.75f, 16); } public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) { - _map = new ConcurrentHashMap>(initialCapacity, loadFactor, concurrencyLevel); + map = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel); } public V get(K key) { V value = null; cleanStaleEntries(); - CacheEntry entry = _map.get(key); + CacheEntry entry = map.get(key); if (entry != null) { value = entry.get(); } @@ -63,11 +64,11 @@ return null; } - CacheEntry newEntry = new CacheEntry(key, newVal, _queue); + CacheEntry newEntry = new CacheEntry<>(key, newVal, queue); while (value == null) { cleanStaleEntries(); - entry = _map.putIfAbsent(key, newEntry); + entry = map.putIfAbsent(key, newEntry); if (entry == null) { value = newVal; break; @@ -79,11 +80,17 @@ return value; } + protected V put(K key, V value) { + CacheEntry entry = new CacheEntry<>(key, value, queue); + CacheEntry oldEntry = map.put(key, entry); + return (oldEntry == null) ? null : oldEntry.get(); + } + @SuppressWarnings("unchecked") private void cleanStaleEntries() { CacheEntry entry; - while ((entry = (CacheEntry)_queue.poll()) != null) { - _map.remove(entry.getKey()); + while ((entry = (CacheEntry)queue.poll()) != null) { + map.remove(entry.getKey()); } } @@ -94,15 +101,15 @@ } private static class CacheEntry extends SoftReference { - private K _key; + private K key; CacheEntry(K key, V value, ReferenceQueue queue) { super(value, queue); - _key = key; + this.key = key; } K getKey() { - return _key; + return key; } } } diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/LocaleSyntaxException.java --- a/jdk/src/share/classes/sun/util/locale/LocaleSyntaxException.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/LocaleSyntaxException.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -35,7 +35,7 @@ private static final long serialVersionUID = 1L; - private int _index = -1; + private int index = -1; public LocaleSyntaxException(String msg) { this(msg, 0); @@ -43,10 +43,10 @@ public LocaleSyntaxException(String msg, int errorIndex) { super(msg); - _index = errorIndex; + index = errorIndex; } public int getErrorIndex() { - return _index; + return index; } } diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/LocaleUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/util/locale/LocaleUtils.java Thu Apr 14 15:59:47 2011 +0900 @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2010, 2011, 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. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +package sun.util.locale; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Collection of static utility methods for Locale support. The + * methods which manipulate characters or strings support ASCII only. + */ +public final class LocaleUtils { + + private LocaleUtils() { + } + + /** + * Compares two ASCII Strings s1 and s2, ignoring case. + */ + public static boolean caseIgnoreMatch(String s1, String s2) { + if (s1 == s2) { + return true; + } + + int len = s1.length(); + if (len != s2.length()) { + return false; + } + + for (int i = 0; i < len; i++) { + char c1 = s1.charAt(i); + char c2 = s2.charAt(i); + if (c1 != c2 && toLower(c1) != toLower(c2)) { + return false; + } + } + return true; + } + + static int caseIgnoreCompare(String s1, String s2) { + if (s1 == s2) { + return 0; + } + return toLowerString(s1).compareTo(toLowerString(s2)); + } + + static char toUpper(char c) { + return isLower(c) ? (char)(c - 0x20) : c; + } + + static char toLower(char c) { + return isUpper(c) ? (char)(c + 0x20) : c; + } + + /** + * Converts the given ASCII String to lower-case. + */ + public static String toLowerString(String s) { + int len = s.length(); + int idx = 0; + for (; idx < len; idx++) { + if (isUpper(s.charAt(idx))) { + break; + } + } + if (idx == len) { + return s; + } + + char[] buf = new char[len]; + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + buf[i] = (i < idx) ? c : toLower(c); + } + return new String(buf); + } + + static String toUpperString(String s) { + int len = s.length(); + int idx = 0; + for (; idx < len; idx++) { + if (isLower(s.charAt(idx))) { + break; + } + } + if (idx == len) { + return s; + } + + char[] buf = new char[len]; + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + buf[i] = (i < idx) ? c : toUpper(c); + } + return new String(buf); + } + + static String toTitleString(String s) { + int len; + if ((len = s.length()) == 0) { + return s; + } + int idx = 0; + if (!isLower(s.charAt(idx))) { + for (idx = 1; idx < len; idx++) { + if (isUpper(s.charAt(idx))) { + break; + } + } + } + if (idx == len) { + return s; + } + + char[] buf = new char[len]; + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + if (i == 0 && idx == 0) { + buf[i] = toUpper(c); + } else if (i < idx) { + buf[i] = c; + } else { + buf[i] = toLower(c); + } + } + return new String(buf); + } + + private static boolean isUpper(char c) { + return c >= 'A' && c <= 'Z'; + } + + private static boolean isLower(char c) { + return c >= 'a' && c <= 'z'; + } + + static boolean isAlpha(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + static boolean isAlphaString(String s) { + int len = s.length(); + for (int i = 0; i < len; i++) { + if (!isAlpha(s.charAt(i))) { + return false; + } + } + return true; + } + + static boolean isNumeric(char c) { + return (c >= '0' && c <= '9'); + } + + static boolean isNumericString(String s) { + int len = s.length(); + for (int i = 0; i < len; i++) { + if (!isNumeric(s.charAt(i))) { + return false; + } + } + return true; + } + + static boolean isAlphaNumeric(char c) { + return isAlpha(c) || isNumeric(c); + } + + static boolean isAlphaNumericString(String s) { + int len = s.length(); + for (int i = 0; i < len; i++) { + if (!isAlphaNumeric(s.charAt(i))) { + return false; + } + } + return true; + } + + static boolean isEmpty(String str) { + return str == null || str.length() == 0; + } + + static boolean isEmpty(Set set) { + return set == null || set.isEmpty(); + } + + static boolean isEmpty(Map map) { + return map == null || map.isEmpty(); + } + + static boolean isEmpty(List list) { + return list == null || list.isEmpty(); + } +} diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/ParseStatus.java --- a/jdk/src/share/classes/sun/util/locale/ParseStatus.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/ParseStatus.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -32,29 +32,33 @@ package sun.util.locale; public class ParseStatus { - int _parseLength = 0; - int _errorIndex = -1; - String _errorMsg = null; + int parseLength; + int errorIndex; + String errorMsg; + + public ParseStatus() { + reset(); + } public void reset() { - _parseLength = 0; - _errorIndex = -1; - _errorMsg = null; + parseLength = 0; + errorIndex = -1; + errorMsg = null; } public boolean isError() { - return (_errorIndex >= 0); + return (errorIndex >= 0); } public int getErrorIndex() { - return _errorIndex; + return errorIndex; } public int getParseLength() { - return _parseLength; + return parseLength; } public String getErrorMessage() { - return _errorMsg; + return errorMsg; } } diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/StringTokenIterator.java --- a/jdk/src/share/classes/sun/util/locale/StringTokenIterator.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/StringTokenIterator.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -31,87 +31,99 @@ package sun.util.locale; public class StringTokenIterator { - private String _text; - private String _dlms; + private String text; + private String dlms; // null if a single char delimiter + private char delimiterChar; // delimiter if a single char delimiter - private String _token; - private int _start; - private int _end; - private boolean _done; + private String token; + private int start; + private int end; + private boolean done; public StringTokenIterator(String text, String dlms) { - _text = text; - _dlms = dlms; + this.text = text; + if (dlms.length() == 1) { + delimiterChar = dlms.charAt(0); + } else { + this.dlms = dlms; + } setStart(0); } public String first() { setStart(0); - return _token; + return token; } public String current() { - return _token; + return token; } public int currentStart() { - return _start; + return start; } public int currentEnd() { - return _end; + return end; } public boolean isDone() { - return _done; + return done; } public String next() { if (hasNext()) { - _start = _end + 1; - _end = nextDelimiter(_start); - _token = _text.substring(_start, _end); + start = end + 1; + end = nextDelimiter(start); + token = text.substring(start, end); } else { - _start = _end; - _token = null; - _done = true; + start = end; + token = null; + done = true; } - return _token; + return token; } public boolean hasNext() { - return (_end < _text.length()); + return (end < text.length()); } public StringTokenIterator setStart(int offset) { - if (offset > _text.length()) { + if (offset > text.length()) { throw new IndexOutOfBoundsException(); } - _start = offset; - _end = nextDelimiter(_start); - _token = _text.substring(_start, _end); - _done = false; + start = offset; + end = nextDelimiter(start); + token = text.substring(start, end); + done = false; return this; } public StringTokenIterator setText(String text) { - _text = text; + this.text = text; setStart(0); return this; } private int nextDelimiter(int start) { - int idx = start; - outer: while (idx < _text.length()) { - char c = _text.charAt(idx); - for (int i = 0; i < _dlms.length(); i++) { - if (c == _dlms.charAt(i)) { - break outer; + int textlen = this.text.length(); + if (dlms == null) { + for (int idx = start; idx < textlen; idx++) { + if (text.charAt(idx) == delimiterChar) { + return idx; } } - idx++; + } else { + int dlmslen = dlms.length(); + for (int idx = start; idx < textlen; idx++) { + char c = text.charAt(idx); + for (int i = 0; i < dlmslen; i++) { + if (c == dlms.charAt(i)) { + return idx; + } + } + } } - return idx; + return textlen; } } - diff -r d331b7996fc3 -r 75c0420badef jdk/src/share/classes/sun/util/locale/UnicodeLocaleExtension.java --- a/jdk/src/share/classes/sun/util/locale/UnicodeLocaleExtension.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/src/share/classes/sun/util/locale/UnicodeLocaleExtension.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,6 @@ + /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -32,56 +33,48 @@ package sun.util.locale; import java.util.Collections; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; public class UnicodeLocaleExtension extends Extension { public static final char SINGLETON = 'u'; - private static final SortedSet EMPTY_SORTED_SET = new TreeSet(); - private static final SortedMap EMPTY_SORTED_MAP = new TreeMap(); - - private SortedSet _attributes = EMPTY_SORTED_SET; - private SortedMap _keywords = EMPTY_SORTED_MAP; - - public static final UnicodeLocaleExtension CA_JAPANESE; - public static final UnicodeLocaleExtension NU_THAI; + private final Set attributes; + private final Map keywords; - static { - CA_JAPANESE = new UnicodeLocaleExtension(); - CA_JAPANESE._keywords = new TreeMap(); - CA_JAPANESE._keywords.put("ca", "japanese"); - CA_JAPANESE._value = "ca-japanese"; + public static final UnicodeLocaleExtension CA_JAPANESE + = new UnicodeLocaleExtension("ca", "japanese"); + public static final UnicodeLocaleExtension NU_THAI + = new UnicodeLocaleExtension("nu", "thai"); - NU_THAI = new UnicodeLocaleExtension(); - NU_THAI._keywords = new TreeMap(); - NU_THAI._keywords.put("nu", "thai"); - NU_THAI._value = "nu-thai"; - } - - private UnicodeLocaleExtension() { - super(SINGLETON); + private UnicodeLocaleExtension(String key, String value) { + super(SINGLETON, key + "-" + value); + attributes = Collections.emptySet(); + keywords = Collections.singletonMap(key, value); } UnicodeLocaleExtension(SortedSet attributes, SortedMap keywords) { - this(); - if (attributes != null && attributes.size() > 0) { - _attributes = attributes; + super(SINGLETON); + if (attributes != null) { + this.attributes = attributes; + } else { + this.attributes = Collections.emptySet(); } - if (keywords != null && keywords.size() > 0) { - _keywords = keywords; + if (keywords != null) { + this.keywords = keywords; + } else { + this.keywords = Collections.emptyMap(); } - if (_attributes.size() > 0 || _keywords.size() > 0) { + if (!this.attributes.isEmpty() || !this.keywords.isEmpty()) { StringBuilder sb = new StringBuilder(); - for (String attribute : _attributes) { + for (String attribute : this.attributes) { sb.append(LanguageTag.SEP).append(attribute); } - for (Entry keyword : _keywords.entrySet()) { + for (Entry keyword : this.keywords.entrySet()) { String key = keyword.getKey(); String value = keyword.getValue(); @@ -90,38 +83,46 @@ sb.append(LanguageTag.SEP).append(value); } } - _value = sb.substring(1); // skip leading '-' + setValue(sb.substring(1)); // skip leading '-' } } public Set getUnicodeLocaleAttributes() { - return Collections.unmodifiableSet(_attributes); + if (attributes == Collections.EMPTY_SET) { + return attributes; + } + return Collections.unmodifiableSet(attributes); } public Set getUnicodeLocaleKeys() { - return Collections.unmodifiableSet(_keywords.keySet()); + if (keywords == Collections.EMPTY_MAP) { + return Collections.emptySet(); + } + return Collections.unmodifiableSet(keywords.keySet()); } public String getUnicodeLocaleType(String unicodeLocaleKey) { - return _keywords.get(unicodeLocaleKey); + return keywords.get(unicodeLocaleKey); } public static boolean isSingletonChar(char c) { - return (SINGLETON == AsciiUtil.toLower(c)); + return (SINGLETON == LocaleUtils.toLower(c)); } public static boolean isAttribute(String s) { // 3*8alphanum - return (s.length() >= 3) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s); + int len = s.length(); + return (len >= 3) && (len <= 8) && LocaleUtils.isAlphaNumericString(s); } public static boolean isKey(String s) { // 2alphanum - return (s.length() == 2) && AsciiUtil.isAlphaNumericString(s); + return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s); } public static boolean isTypeSubtag(String s) { // 3*8alphanum - return (s.length() >= 3) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s); + int len = s.length(); + return (len >= 3) && (len <= 8) && LocaleUtils.isAlphaNumericString(s); } } diff -r d331b7996fc3 -r 75c0420badef jdk/test/java/util/Locale/LocaleEnhanceTest.java --- a/jdk/test/java/util/Locale/LocaleEnhanceTest.java Wed Apr 13 21:08:08 2011 +0400 +++ b/jdk/test/java/util/Locale/LocaleEnhanceTest.java Thu Apr 14 15:59:47 2011 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -33,8 +33,10 @@ import java.io.ObjectOutputStream; import java.net.URISyntaxException; import java.net.URL; +import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.IllformedLocaleException; import java.util.List; import java.util.Locale; @@ -43,8 +45,10 @@ /** * @test - * @bug 6875847 6992272 7002320 7015500 7023613 + * @bug 6875847 6992272 7002320 7015500 7023613 7032820 7033504 * @summary test API changes to Locale + * @compile LocaleEnhanceTest.java + * @run main/othervm -esa LocaleEnhanceTest */ public class LocaleEnhanceTest extends LocaleTestFmwk { @@ -593,6 +597,9 @@ assertEquals("extension", "aa-00-bb-01", locale.getExtension('d')); assertEquals("extension c", "1234", locale.getExtension('c')); + locale = Locale.forLanguageTag("und-U-ca-gregory-u-ca-japanese"); + assertEquals("Unicode extension", "ca-gregory", locale.getExtension(Locale.UNICODE_LOCALE_EXTENSION)); + // redundant Unicode locale keys in an extension are ignored locale = Locale.forLanguageTag("und-u-aa-000-bb-001-bB-002-cc-003-c-1234"); assertEquals("Unicode keywords", "aa-000-bb-001-cc-003", locale.getExtension(Locale.UNICODE_LOCALE_EXTENSION)); @@ -1275,6 +1282,35 @@ } } + /* + * 7033504: (lc) incompatible behavior change for ja_JP_JP and th_TH_TH locales + */ + public void testBug7033504() { + checkCalendar(new Locale("ja", "JP", "jp"), "java.util.GregorianCalendar"); + checkCalendar(new Locale("ja", "jp", "jp"), "java.util.GregorianCalendar"); + checkCalendar(new Locale("ja", "JP", "JP"), "java.util.JapaneseImperialCalendar"); + checkCalendar(new Locale("ja", "jp", "JP"), "java.util.JapaneseImperialCalendar"); + checkCalendar(Locale.forLanguageTag("en-u-ca-japanese"), + "java.util.JapaneseImperialCalendar"); + + checkDigit(new Locale("th", "TH", "th"), '0'); + checkDigit(new Locale("th", "th", "th"), '0'); + checkDigit(new Locale("th", "TH", "TH"), '\u0e50'); + checkDigit(new Locale("th", "TH", "TH"), '\u0e50'); + checkDigit(Locale.forLanguageTag("en-u-nu-thai"), '\u0e50'); + } + + private void checkCalendar(Locale loc, String expected) { + Calendar cal = Calendar.getInstance(loc); + assertEquals("Wrong calendar", expected, cal.getClass().getName()); + } + + private void checkDigit(Locale loc, Character expected) { + DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(loc); + Character zero = dfs.getZeroDigit(); + assertEquals("Wrong digit zero char", expected, zero); + } + /// /// utility asserts ///