提交 7186bcf5 编写于 作者: O okutsu

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
上级 e9f30601
# #
# 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. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -189,7 +189,6 @@ JAVA_JAVA_java = \ ...@@ -189,7 +189,6 @@ JAVA_JAVA_java = \
java/util/ListResourceBundle.java \ java/util/ListResourceBundle.java \
sun/util/EmptyListResourceBundle.java \ sun/util/EmptyListResourceBundle.java \
java/util/Locale.java \ java/util/Locale.java \
sun/util/locale/AsciiUtil.java \
sun/util/locale/BaseLocale.java \ sun/util/locale/BaseLocale.java \
sun/util/locale/Extension.java \ sun/util/locale/Extension.java \
sun/util/locale/InternalLocaleBuilder.java \ sun/util/locale/InternalLocaleBuilder.java \
...@@ -197,6 +196,7 @@ JAVA_JAVA_java = \ ...@@ -197,6 +196,7 @@ JAVA_JAVA_java = \
sun/util/locale/LocaleExtensions.java \ sun/util/locale/LocaleExtensions.java \
sun/util/locale/LocaleObjectCache.java \ sun/util/locale/LocaleObjectCache.java \
sun/util/locale/LocaleSyntaxException.java \ sun/util/locale/LocaleSyntaxException.java \
sun/util/locale/LocaleUtils.java \
sun/util/locale/ParseStatus.java \ sun/util/locale/ParseStatus.java \
sun/util/locale/StringTokenIterator.java \ sun/util/locale/StringTokenIterator.java \
sun/util/locale/UnicodeLocaleExtension.java \ sun/util/locale/UnicodeLocaleExtension.java \
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -57,7 +57,6 @@ import java.util.concurrent.ConcurrentMap; ...@@ -57,7 +57,6 @@ import java.util.concurrent.ConcurrentMap;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import sun.util.locale.BaseLocale; import sun.util.locale.BaseLocale;
import sun.util.locale.LocaleExtensions;
import sun.util.locale.LocaleObjectCache; import sun.util.locale.LocaleObjectCache;
...@@ -290,7 +289,7 @@ public abstract class ResourceBundle { ...@@ -290,7 +289,7 @@ public abstract class ResourceBundle {
* name for compatibility with some workarounds for bug 4212439. * name for compatibility with some workarounds for bug 4212439.
*/ */
private static final ConcurrentMap<CacheKey, BundleReference> cacheList private static final ConcurrentMap<CacheKey, BundleReference> cacheList
= new ConcurrentHashMap<CacheKey, BundleReference>(INITIAL_CACHE_SIZE); = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
/** /**
* Queue for reference objects referring to class loaders or bundles. * Queue for reference objects referring to class loaders or bundles.
...@@ -1755,7 +1754,7 @@ public abstract class ResourceBundle { ...@@ -1755,7 +1754,7 @@ public abstract class ResourceBundle {
* @since 1.6 * @since 1.6
*/ */
public Set<String> keySet() { public Set<String> keySet() {
Set<String> keys = new HashSet<String>(); Set<String> keys = new HashSet<>();
for (ResourceBundle rb = this; rb != null; rb = rb.parent) { for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
keys.addAll(rb.handleKeySet()); keys.addAll(rb.handleKeySet());
} }
...@@ -1783,7 +1782,7 @@ public abstract class ResourceBundle { ...@@ -1783,7 +1782,7 @@ public abstract class ResourceBundle {
if (keySet == null) { if (keySet == null) {
synchronized (this) { synchronized (this) {
if (keySet == null) { if (keySet == null) {
Set<String> keys = new HashSet<String>(); Set<String> keys = new HashSet<>();
Enumeration<String> enumKeys = getKeys(); Enumeration<String> enumKeys = getKeys();
while (enumKeys.hasMoreElements()) { while (enumKeys.hasMoreElements()) {
String key = enumKeys.nextElement(); String key = enumKeys.nextElement();
...@@ -2301,7 +2300,7 @@ public abstract class ResourceBundle { ...@@ -2301,7 +2300,7 @@ public abstract class ResourceBundle {
if (baseName == null) { if (baseName == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
return new ArrayList<Locale>(CANDIDATES_CACHE.get(locale.getBaseLocale())); return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
} }
private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache(); private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
...@@ -2327,14 +2326,14 @@ public abstract class ResourceBundle { ...@@ -2327,14 +2326,14 @@ public abstract class ResourceBundle {
if (language.equals("nb") || isNorwegianBokmal) { if (language.equals("nb") || isNorwegianBokmal) {
List<Locale> tmpList = getDefaultList("nb", script, region, variant); List<Locale> tmpList = getDefaultList("nb", script, region, variant);
// Insert a locale replacing "nb" with "no" for every list entry // Insert a locale replacing "nb" with "no" for every list entry
List<Locale> bokmalList = new LinkedList<Locale>(); List<Locale> bokmalList = new LinkedList<>();
for (Locale l : tmpList) { for (Locale l : tmpList) {
bokmalList.add(l); bokmalList.add(l);
if (l.getLanguage().length() == 0) { if (l.getLanguage().length() == 0) {
break; break;
} }
bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(), bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
l.getVariant(), LocaleExtensions.EMPTY_EXTENSIONS)); l.getVariant(), null));
} }
return bokmalList; return bokmalList;
} else if (language.equals("nn") || isNorwegianNynorsk) { } else if (language.equals("nn") || isNorwegianNynorsk) {
...@@ -2374,7 +2373,7 @@ public abstract class ResourceBundle { ...@@ -2374,7 +2373,7 @@ public abstract class ResourceBundle {
List<String> variants = null; List<String> variants = null;
if (variant.length() > 0) { if (variant.length() > 0) {
variants = new LinkedList<String>(); variants = new LinkedList<>();
int idx = variant.length(); int idx = variant.length();
while (idx != -1) { while (idx != -1) {
variants.add(variant.substring(0, idx)); variants.add(variant.substring(0, idx));
...@@ -2382,32 +2381,32 @@ public abstract class ResourceBundle { ...@@ -2382,32 +2381,32 @@ public abstract class ResourceBundle {
} }
} }
LinkedList<Locale> list = new LinkedList<Locale>(); List<Locale> list = new LinkedList<>();
if (variants != null) { if (variants != null) {
for (String v : variants) { 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) { 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) { 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, // With script, after truncating variant, region and script,
// start over without script. // start over without script.
if (variants != null) { if (variants != null) {
for (String v : variants) { 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) { if (region.length() > 0) {
list.add(Locale.getInstance(language, "", region, "", LocaleExtensions.EMPTY_EXTENSIONS)); list.add(Locale.getInstance(language, "", region, "", null));
} }
} }
if (language.length() > 0) { if (language.length() > 0) {
list.add(Locale.getInstance(language, "", "", "", LocaleExtensions.EMPTY_EXTENSIONS)); list.add(Locale.getInstance(language, "", "", "", null));
} }
// Add root locale at the end // Add root locale at the end
list.add(Locale.ROOT); list.add(Locale.ROOT);
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -38,38 +38,46 @@ public final class BaseLocale { ...@@ -38,38 +38,46 @@ public final class BaseLocale {
public static final String SEP = "_"; public static final String SEP = "_";
private static final Cache CACHE = new Cache(); private static final Cache CACHE = new Cache();
public static final BaseLocale ROOT = BaseLocale.getInstance("", "", "", "");
private String _language = ""; private final String language;
private String _script = ""; private final String script;
private String _region = ""; private final String region;
private String _variant = ""; private final String variant;
private transient volatile int _hash = 0; private 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) { private BaseLocale(String language, String script, String region, String variant) {
if (language != null) { this.language = (language != null) ? LocaleUtils.toLowerString(language).intern() : "";
_language = AsciiUtil.toLowerString(language).intern(); this.script = (script != null) ? LocaleUtils.toTitleString(script).intern() : "";
} this.region = (region != null) ? LocaleUtils.toUpperString(region).intern() : "";
if (script != null) { this.variant = (variant != null) ? variant.intern() : "";
_script = AsciiUtil.toTitleString(script).intern(); }
}
if (region != null) { // Called for creating the Locale.* constants. No argument
_region = AsciiUtil.toUpperString(region).intern(); // validation is performed.
} public static BaseLocale createInstance(String language, String region) {
if (variant != null) { BaseLocale base = new BaseLocale(language, region);
_variant = variant.intern(); CACHE.put(new Key(language, region), base);
} return base;
} }
public static BaseLocale getInstance(String language, String script, String region, String variant) { public static BaseLocale getInstance(String language, String script,
String region, String variant) {
// JDK uses deprecated ISO639.1 language codes for he, yi and id // JDK uses deprecated ISO639.1 language codes for he, yi and id
if (language != null) { if (language != null) {
if (AsciiUtil.caseIgnoreMatch(language, "he")) { if (LocaleUtils.caseIgnoreMatch(language, "he")) {
language = "iw"; language = "iw";
} else if (AsciiUtil.caseIgnoreMatch(language, "yi")) { } else if (LocaleUtils.caseIgnoreMatch(language, "yi")) {
language = "ji"; language = "ji";
} else if (AsciiUtil.caseIgnoreMatch(language, "id")) { } else if (LocaleUtils.caseIgnoreMatch(language, "id")) {
language = "in"; language = "in";
} }
} }
...@@ -80,21 +88,22 @@ public final class BaseLocale { ...@@ -80,21 +88,22 @@ public final class BaseLocale {
} }
public String getLanguage() { public String getLanguage() {
return _language; return language;
} }
public String getScript() { public String getScript() {
return _script; return script;
} }
public String getRegion() { public String getRegion() {
return _region; return region;
} }
public String getVariant() { public String getVariant() {
return _variant; return variant;
} }
@Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
...@@ -103,138 +112,178 @@ public final class BaseLocale { ...@@ -103,138 +112,178 @@ public final class BaseLocale {
return false; return false;
} }
BaseLocale other = (BaseLocale)obj; BaseLocale other = (BaseLocale)obj;
return hashCode() == other.hashCode() return language == other.language
&& _language.equals(other._language) && script == other.script
&& _script.equals(other._script) && region == other.region
&& _region.equals(other._region) && variant == other.variant;
&& _variant.equals(other._variant);
} }
@Override
public String toString() { public String toString() {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
if (_language.length() > 0) { if (language.length() > 0) {
buf.append("language="); buf.append("language=");
buf.append(_language); buf.append(language);
} }
if (_script.length() > 0) { if (script.length() > 0) {
if (buf.length() > 0) { if (buf.length() > 0) {
buf.append(", "); buf.append(", ");
} }
buf.append("script="); buf.append("script=");
buf.append(_script); buf.append(script);
} }
if (_region.length() > 0) { if (region.length() > 0) {
if (buf.length() > 0) { if (buf.length() > 0) {
buf.append(", "); buf.append(", ");
} }
buf.append("region="); buf.append("region=");
buf.append(_region); buf.append(region);
} }
if (_variant.length() > 0) { if (variant.length() > 0) {
if (buf.length() > 0) { if (buf.length() > 0) {
buf.append(", "); buf.append(", ");
} }
buf.append("variant="); buf.append("variant=");
buf.append(_variant); buf.append(variant);
} }
return buf.toString(); return buf.toString();
} }
@Override
public int hashCode() { public int hashCode() {
int h = _hash; int h = hash;
if (h == 0) { if (h == 0) {
// Generating a hash value from language, script, region and variant // Generating a hash value from language, script, region and variant
for (int i = 0; i < _language.length(); i++) { h = language.hashCode();
h = 31*h + _language.charAt(i); h = 31 * h + script.hashCode();
} h = 31 * h + region.hashCode();
for (int i = 0; i < _script.length(); i++) { h = 31 * h + variant.hashCode();
h = 31*h + _script.charAt(i); hash = h;
}
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;
} }
return h; return h;
} }
private static class Key implements Comparable<Key> { private static final class Key implements Comparable<Key> {
private String _lang = ""; private final String lang;
private String _scrt = ""; private final String scrt;
private String _regn = ""; private final String regn;
private String _vart = ""; 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) { 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) { 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) { 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) { 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) { 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) { public boolean equals(Object obj) {
return (this == obj) || return (this == obj) ||
(obj instanceof Key) (obj instanceof Key)
&& AsciiUtil.caseIgnoreMatch(((Key)obj)._lang, this._lang) && this.hash == ((Key)obj).hash
&& AsciiUtil.caseIgnoreMatch(((Key)obj)._scrt, this._scrt) && LocaleUtils.caseIgnoreMatch(((Key)obj).lang, this.lang)
&& AsciiUtil.caseIgnoreMatch(((Key)obj)._regn, this._regn) && LocaleUtils.caseIgnoreMatch(((Key)obj).scrt, this.scrt)
&& ((Key)obj)._vart.equals(_vart); // variant is case sensitive in JDK! && LocaleUtils.caseIgnoreMatch(((Key)obj).regn, this.regn)
&& ((Key)obj).vart.equals(vart); // variant is case sensitive in JDK!
} }
@Override
public int compareTo(Key other) { public int compareTo(Key other) {
int res = AsciiUtil.caseIgnoreCompare(this._lang, other._lang); int res = LocaleUtils.caseIgnoreCompare(this.lang, other.lang);
if (res == 0) { if (res == 0) {
res = AsciiUtil.caseIgnoreCompare(this._scrt, other._scrt); res = LocaleUtils.caseIgnoreCompare(this.scrt, other.scrt);
if (res == 0) { if (res == 0) {
res = AsciiUtil.caseIgnoreCompare(this._regn, other._regn); res = LocaleUtils.caseIgnoreCompare(this.regn, other.regn);
if (res == 0) { if (res == 0) {
res = this._vart.compareTo(other._vart); res = this.vart.compareTo(other.vart);
} }
} }
} }
return res; return res;
} }
@Override
public int hashCode() { public int hashCode() {
int h = _hash; return 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;
} }
public static Key normalize(Key key) { public static Key normalize(Key key) {
String lang = AsciiUtil.toLowerString(key._lang).intern(); if (key.normalized) {
String scrt = AsciiUtil.toTitleString(key._scrt).intern(); return key;
String regn = AsciiUtil.toUpperString(key._regn).intern(); }
String vart = key._vart.intern(); // preserve upper/lower cases
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 final class BaseLocale { ...@@ -243,13 +292,14 @@ public final class BaseLocale {
public Cache() { public Cache() {
} }
@Override
protected Key normalizeKey(Key key) { protected Key normalizeKey(Key key) {
return Key.normalize(key); return Key.normalize(key);
} }
@Override
protected BaseLocale createObject(Key key) { 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);
} }
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -32,29 +32,34 @@ ...@@ -32,29 +32,34 @@
package sun.util.locale; package sun.util.locale;
public class Extension { class Extension {
private char _key; private final char key;
protected String _value; private String value, id;
protected Extension(char key) { protected Extension(char key) {
_key = key; this.key = key;
} }
Extension(char key, String value) { Extension(char key, String value) {
_key = key; this.key = key;
_value = value; setValue(value);
}
protected void setValue(String value) {
this.value = value;
this.id = key + LanguageTag.SEP + value;
} }
public char getKey() { public char getKey() {
return _key; return key;
} }
public String getValue() { public String getValue() {
return _value; return value;
} }
public String getID() { public String getID() {
return _key + LanguageTag.SEP + _value; return id;
} }
public String toString() { public String toString() {
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -36,6 +36,7 @@ import java.util.Map; ...@@ -36,6 +36,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
...@@ -45,55 +46,45 @@ import sun.util.locale.InternalLocaleBuilder.CaseInsensitiveString; ...@@ -45,55 +46,45 @@ import sun.util.locale.InternalLocaleBuilder.CaseInsensitiveString;
public class LocaleExtensions { public class LocaleExtensions {
private SortedMap<Character, Extension> _map; private final Map<Character, Extension> extensionMap;
private String _id; private final String id;
private static final SortedMap<Character, Extension> EMPTY_MAP = public static final LocaleExtensions CALENDAR_JAPANESE
Collections.unmodifiableSortedMap(new TreeMap<Character, Extension>()); = new LocaleExtensions("u-ca-japanese",
UnicodeLocaleExtension.SINGLETON,
UnicodeLocaleExtension.CA_JAPANESE);
public static final LocaleExtensions EMPTY_EXTENSIONS; public static final LocaleExtensions NUMBER_THAI
public static final LocaleExtensions CALENDAR_JAPANESE; = new LocaleExtensions("u-nu-thai",
public static final LocaleExtensions NUMBER_THAI; UnicodeLocaleExtension.SINGLETON,
UnicodeLocaleExtension.NU_THAI);
static { private LocaleExtensions(String id, Character key, Extension value) {
EMPTY_EXTENSIONS = new LocaleExtensions(); this.id = id;
EMPTY_EXTENSIONS._id = ""; this.extensionMap = Collections.singletonMap(key, value);
EMPTY_EXTENSIONS._map = EMPTY_MAP;
CALENDAR_JAPANESE = new LocaleExtensions();
CALENDAR_JAPANESE._id = "u-ca-japanese";
CALENDAR_JAPANESE._map = new TreeMap<Character, Extension>();
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<Character, Extension>();
NUMBER_THAI._map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), UnicodeLocaleExtension.NU_THAI);
}
private LocaleExtensions() {
} }
/* /*
* Package local constructor, only used by InternalLocaleBuilder. * Package private constructor, only used by InternalLocaleBuilder.
*/ */
LocaleExtensions(Map<CaseInsensitiveChar, String> extensions, LocaleExtensions(Map<CaseInsensitiveChar, String> extensions,
Set<CaseInsensitiveString> uattributes, Map<CaseInsensitiveString, String> ukeywords) { Set<CaseInsensitiveString> uattributes,
boolean hasExtension = (extensions != null && extensions.size() > 0); Map<CaseInsensitiveString, String> ukeywords) {
boolean hasUAttributes = (uattributes != null && uattributes.size() > 0); boolean hasExtension = !LocaleUtils.isEmpty(extensions);
boolean hasUKeywords = (ukeywords != null && ukeywords.size() > 0); boolean hasUAttributes = !LocaleUtils.isEmpty(uattributes);
boolean hasUKeywords = !LocaleUtils.isEmpty(ukeywords);
if (!hasExtension && !hasUAttributes && !hasUKeywords) { if (!hasExtension && !hasUAttributes && !hasUKeywords) {
_map = EMPTY_MAP; id = "";
_id = ""; extensionMap = Collections.emptyMap();
return; return;
} }
// Build extension map // Build extension map
_map = new TreeMap<Character, Extension>(); SortedMap<Character, Extension> map = new TreeMap<>();
if (hasExtension) { if (hasExtension) {
for (Entry<CaseInsensitiveChar, String> ext : extensions.entrySet()) { for (Entry<CaseInsensitiveChar, String> ext : extensions.entrySet()) {
char key = AsciiUtil.toLower(ext.getKey().value()); char key = LocaleUtils.toLower(ext.getKey().value());
String value = ext.getValue(); String value = ext.getValue();
if (LanguageTag.isPrivateusePrefixChar(key)) { if (LanguageTag.isPrivateusePrefixChar(key)) {
...@@ -104,54 +95,57 @@ public class LocaleExtensions { ...@@ -104,54 +95,57 @@ public class LocaleExtensions {
} }
} }
Extension e = new Extension(key, AsciiUtil.toLowerString(value)); map.put(key, new Extension(key, LocaleUtils.toLowerString(value)));
_map.put(Character.valueOf(key), e);
} }
} }
if (hasUAttributes || hasUKeywords) { if (hasUAttributes || hasUKeywords) {
TreeSet<String> uaset = null; SortedSet<String> uaset = null;
TreeMap<String, String> ukmap = null; SortedMap<String, String> ukmap = null;
if (hasUAttributes) { if (hasUAttributes) {
uaset = new TreeSet<String>(); uaset = new TreeSet<>();
for (CaseInsensitiveString cis : uattributes) { for (CaseInsensitiveString cis : uattributes) {
uaset.add(AsciiUtil.toLowerString(cis.value())); uaset.add(LocaleUtils.toLowerString(cis.value()));
} }
} }
if (hasUKeywords) { if (hasUKeywords) {
ukmap = new TreeMap<String, String>(); ukmap = new TreeMap<>();
for (Entry<CaseInsensitiveString, String> kwd : ukeywords.entrySet()) { for (Entry<CaseInsensitiveString, String> kwd : ukeywords.entrySet()) {
String key = AsciiUtil.toLowerString(kwd.getKey().value()); String key = LocaleUtils.toLowerString(kwd.getKey().value());
String type = AsciiUtil.toLowerString(kwd.getValue()); String type = LocaleUtils.toLowerString(kwd.getValue());
ukmap.put(key, type); ukmap.put(key, type);
} }
} }
UnicodeLocaleExtension ule = new UnicodeLocaleExtension(uaset, ukmap); 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 // this could happen when only privuateuse with special variant
_map = EMPTY_MAP; id = "";
_id = ""; extensionMap = Collections.emptyMap();
} else { } else {
_id = toID(_map); id = toID(map);
extensionMap = map;
} }
} }
public Set<Character> getKeys() { public Set<Character> getKeys() {
return Collections.unmodifiableSet(_map.keySet()); if (extensionMap.isEmpty()) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(extensionMap.keySet());
} }
public Extension getExtension(Character key) { 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) { 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) { if (ext == null) {
return null; return null;
} }
...@@ -159,7 +153,7 @@ public class LocaleExtensions { ...@@ -159,7 +153,7 @@ public class LocaleExtensions {
} }
public Set<String> getUnicodeLocaleAttributes() { public Set<String> getUnicodeLocaleAttributes() {
Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON);
if (ext == null) { if (ext == null) {
return Collections.emptySet(); return Collections.emptySet();
} }
...@@ -168,7 +162,7 @@ public class LocaleExtensions { ...@@ -168,7 +162,7 @@ public class LocaleExtensions {
} }
public Set<String> getUnicodeLocaleKeys() { public Set<String> getUnicodeLocaleKeys() {
Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON);
if (ext == null) { if (ext == null) {
return Collections.emptySet(); return Collections.emptySet();
} }
...@@ -177,16 +171,16 @@ public class LocaleExtensions { ...@@ -177,16 +171,16 @@ public class LocaleExtensions {
} }
public String getUnicodeLocaleType(String unicodeLocaleKey) { public String getUnicodeLocaleType(String unicodeLocaleKey) {
Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); Extension ext = extensionMap.get(UnicodeLocaleExtension.SINGLETON);
if (ext == null) { if (ext == null) {
return null; return null;
} }
assert (ext instanceof UnicodeLocaleExtension); assert (ext instanceof UnicodeLocaleExtension);
return ((UnicodeLocaleExtension)ext).getUnicodeLocaleType(AsciiUtil.toLowerString(unicodeLocaleKey)); return ((UnicodeLocaleExtension)ext).getUnicodeLocaleType(LocaleUtils.toLowerString(unicodeLocaleKey));
} }
public boolean isEmpty() { public boolean isEmpty() {
return _map.isEmpty(); return extensionMap.isEmpty();
} }
public static boolean isValidKey(char c) { public static boolean isValidKey(char c) {
...@@ -201,7 +195,7 @@ public class LocaleExtensions { ...@@ -201,7 +195,7 @@ public class LocaleExtensions {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
Extension privuse = null; Extension privuse = null;
for (Entry<Character, Extension> entry : map.entrySet()) { for (Entry<Character, Extension> entry : map.entrySet()) {
char singleton = entry.getKey().charValue(); char singleton = entry.getKey();
Extension extension = entry.getValue(); Extension extension = entry.getValue();
if (LanguageTag.isPrivateusePrefixChar(singleton)) { if (LanguageTag.isPrivateusePrefixChar(singleton)) {
privuse = extension; privuse = extension;
...@@ -221,19 +215,21 @@ public class LocaleExtensions { ...@@ -221,19 +215,21 @@ public class LocaleExtensions {
return buf.toString(); return buf.toString();
} }
@Override
public String toString() { public String toString() {
return _id; return id;
} }
public String getID() { public String getID() {
return _id; return id;
} }
@Override
public int hashCode() { public int hashCode() {
return _id.hashCode(); return id.hashCode();
} }
@Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (this == other) { if (this == other) {
return true; return true;
...@@ -241,6 +237,6 @@ public class LocaleExtensions { ...@@ -241,6 +237,6 @@ public class LocaleExtensions {
if (!(other instanceof LocaleExtensions)) { if (!(other instanceof LocaleExtensions)) {
return false; return false;
} }
return this._id.equals(((LocaleExtensions)other)._id); return id.equals(((LocaleExtensions)other).id);
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -34,24 +34,25 @@ package sun.util.locale; ...@@ -34,24 +34,25 @@ package sun.util.locale;
import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public abstract class LocaleObjectCache<K, V> { public abstract class LocaleObjectCache<K, V> {
private ConcurrentHashMap<K, CacheEntry<K, V>> _map; private ConcurrentMap<K, CacheEntry<K, V>> map;
private ReferenceQueue<V> _queue = new ReferenceQueue<V>(); private ReferenceQueue<V> queue = new ReferenceQueue<>();
public LocaleObjectCache() { public LocaleObjectCache() {
this(16, 0.75f, 16); this(16, 0.75f, 16);
} }
public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) { public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) {
_map = new ConcurrentHashMap<K, CacheEntry<K, V>>(initialCapacity, loadFactor, concurrencyLevel); map = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel);
} }
public V get(K key) { public V get(K key) {
V value = null; V value = null;
cleanStaleEntries(); cleanStaleEntries();
CacheEntry<K, V> entry = _map.get(key); CacheEntry<K, V> entry = map.get(key);
if (entry != null) { if (entry != null) {
value = entry.get(); value = entry.get();
} }
...@@ -63,11 +64,11 @@ public abstract class LocaleObjectCache<K, V> { ...@@ -63,11 +64,11 @@ public abstract class LocaleObjectCache<K, V> {
return null; return null;
} }
CacheEntry<K, V> newEntry = new CacheEntry<K, V>(key, newVal, _queue); CacheEntry<K, V> newEntry = new CacheEntry<>(key, newVal, queue);
while (value == null) { while (value == null) {
cleanStaleEntries(); cleanStaleEntries();
entry = _map.putIfAbsent(key, newEntry); entry = map.putIfAbsent(key, newEntry);
if (entry == null) { if (entry == null) {
value = newVal; value = newVal;
break; break;
...@@ -79,11 +80,17 @@ public abstract class LocaleObjectCache<K, V> { ...@@ -79,11 +80,17 @@ public abstract class LocaleObjectCache<K, V> {
return value; return value;
} }
protected V put(K key, V value) {
CacheEntry<K, V> entry = new CacheEntry<>(key, value, queue);
CacheEntry<K, V> oldEntry = map.put(key, entry);
return (oldEntry == null) ? null : oldEntry.get();
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void cleanStaleEntries() { private void cleanStaleEntries() {
CacheEntry<K, V> entry; CacheEntry<K, V> entry;
while ((entry = (CacheEntry<K, V>)_queue.poll()) != null) { while ((entry = (CacheEntry<K, V>)queue.poll()) != null) {
_map.remove(entry.getKey()); map.remove(entry.getKey());
} }
} }
...@@ -94,15 +101,15 @@ public abstract class LocaleObjectCache<K, V> { ...@@ -94,15 +101,15 @@ public abstract class LocaleObjectCache<K, V> {
} }
private static class CacheEntry<K, V> extends SoftReference<V> { private static class CacheEntry<K, V> extends SoftReference<V> {
private K _key; private K key;
CacheEntry(K key, V value, ReferenceQueue<V> queue) { CacheEntry(K key, V value, ReferenceQueue<V> queue) {
super(value, queue); super(value, queue);
_key = key; this.key = key;
} }
K getKey() { K getKey() {
return _key; return key;
} }
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -35,7 +35,7 @@ public class LocaleSyntaxException extends Exception { ...@@ -35,7 +35,7 @@ public class LocaleSyntaxException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private int _index = -1; private int index = -1;
public LocaleSyntaxException(String msg) { public LocaleSyntaxException(String msg) {
this(msg, 0); this(msg, 0);
...@@ -43,10 +43,10 @@ public class LocaleSyntaxException extends Exception { ...@@ -43,10 +43,10 @@ public class LocaleSyntaxException extends Exception {
public LocaleSyntaxException(String msg, int errorIndex) { public LocaleSyntaxException(String msg, int errorIndex) {
super(msg); super(msg);
_index = errorIndex; index = errorIndex;
} }
public int getErrorIndex() { public int getErrorIndex() {
return _index; return index;
} }
} }
/*
* 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();
}
}
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -32,29 +32,33 @@ ...@@ -32,29 +32,33 @@
package sun.util.locale; package sun.util.locale;
public class ParseStatus { public class ParseStatus {
int _parseLength = 0; int parseLength;
int _errorIndex = -1; int errorIndex;
String _errorMsg = null; String errorMsg;
public ParseStatus() {
reset();
}
public void reset() { public void reset() {
_parseLength = 0; parseLength = 0;
_errorIndex = -1; errorIndex = -1;
_errorMsg = null; errorMsg = null;
} }
public boolean isError() { public boolean isError() {
return (_errorIndex >= 0); return (errorIndex >= 0);
} }
public int getErrorIndex() { public int getErrorIndex() {
return _errorIndex; return errorIndex;
} }
public int getParseLength() { public int getParseLength() {
return _parseLength; return parseLength;
} }
public String getErrorMessage() { public String getErrorMessage() {
return _errorMsg; return errorMsg;
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -31,87 +31,99 @@ ...@@ -31,87 +31,99 @@
package sun.util.locale; package sun.util.locale;
public class StringTokenIterator { public class StringTokenIterator {
private String _text; private String text;
private String _dlms; private String dlms; // null if a single char delimiter
private char delimiterChar; // delimiter if a single char delimiter
private String _token; private String token;
private int _start; private int start;
private int _end; private int end;
private boolean _done; private boolean done;
public StringTokenIterator(String text, String dlms) { public StringTokenIterator(String text, String dlms) {
_text = text; this.text = text;
_dlms = dlms; if (dlms.length() == 1) {
delimiterChar = dlms.charAt(0);
} else {
this.dlms = dlms;
}
setStart(0); setStart(0);
} }
public String first() { public String first() {
setStart(0); setStart(0);
return _token; return token;
} }
public String current() { public String current() {
return _token; return token;
} }
public int currentStart() { public int currentStart() {
return _start; return start;
} }
public int currentEnd() { public int currentEnd() {
return _end; return end;
} }
public boolean isDone() { public boolean isDone() {
return _done; return done;
} }
public String next() { public String next() {
if (hasNext()) { if (hasNext()) {
_start = _end + 1; start = end + 1;
_end = nextDelimiter(_start); end = nextDelimiter(start);
_token = _text.substring(_start, _end); token = text.substring(start, end);
} else { } else {
_start = _end; start = end;
_token = null; token = null;
_done = true; done = true;
} }
return _token; return token;
} }
public boolean hasNext() { public boolean hasNext() {
return (_end < _text.length()); return (end < text.length());
} }
public StringTokenIterator setStart(int offset) { public StringTokenIterator setStart(int offset) {
if (offset > _text.length()) { if (offset > text.length()) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
_start = offset; start = offset;
_end = nextDelimiter(_start); end = nextDelimiter(start);
_token = _text.substring(_start, _end); token = text.substring(start, end);
_done = false; done = false;
return this; return this;
} }
public StringTokenIterator setText(String text) { public StringTokenIterator setText(String text) {
_text = text; this.text = text;
setStart(0); setStart(0);
return this; return this;
} }
private int nextDelimiter(int start) { private int nextDelimiter(int start) {
int idx = start; int textlen = this.text.length();
outer: while (idx < _text.length()) { if (dlms == null) {
char c = _text.charAt(idx); for (int idx = start; idx < textlen; idx++) {
for (int i = 0; i < _dlms.length(); i++) { if (text.charAt(idx) == delimiterChar) {
if (c == _dlms.charAt(i)) { return idx;
break outer; }
}
} 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;
}
} }
} }
idx++;
} }
return idx; return textlen;
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -32,56 +33,48 @@ ...@@ -32,56 +33,48 @@
package sun.util.locale; package sun.util.locale;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
public class UnicodeLocaleExtension extends Extension { public class UnicodeLocaleExtension extends Extension {
public static final char SINGLETON = 'u'; public static final char SINGLETON = 'u';
private static final SortedSet<String> EMPTY_SORTED_SET = new TreeSet<String>(); private final Set<String> attributes;
private static final SortedMap<String, String> EMPTY_SORTED_MAP = new TreeMap<String, String>(); private final Map<String, String> keywords;
private SortedSet<String> _attributes = EMPTY_SORTED_SET;
private SortedMap<String, String> _keywords = EMPTY_SORTED_MAP;
public static final UnicodeLocaleExtension CA_JAPANESE;
public static final UnicodeLocaleExtension NU_THAI;
static { public static final UnicodeLocaleExtension CA_JAPANESE
CA_JAPANESE = new UnicodeLocaleExtension(); = new UnicodeLocaleExtension("ca", "japanese");
CA_JAPANESE._keywords = new TreeMap<String, String>(); public static final UnicodeLocaleExtension NU_THAI
CA_JAPANESE._keywords.put("ca", "japanese"); = new UnicodeLocaleExtension("nu", "thai");
CA_JAPANESE._value = "ca-japanese";
NU_THAI = new UnicodeLocaleExtension(); private UnicodeLocaleExtension(String key, String value) {
NU_THAI._keywords = new TreeMap<String, String>(); super(SINGLETON, key + "-" + value);
NU_THAI._keywords.put("nu", "thai"); attributes = Collections.emptySet();
NU_THAI._value = "nu-thai"; keywords = Collections.singletonMap(key, value);
}
private UnicodeLocaleExtension() {
super(SINGLETON);
} }
UnicodeLocaleExtension(SortedSet<String> attributes, SortedMap<String, String> keywords) { UnicodeLocaleExtension(SortedSet<String> attributes, SortedMap<String, String> keywords) {
this(); super(SINGLETON);
if (attributes != null && attributes.size() > 0) { if (attributes != null) {
_attributes = attributes; this.attributes = attributes;
} else {
this.attributes = Collections.emptySet();
} }
if (keywords != null && keywords.size() > 0) { if (keywords != null) {
_keywords = keywords; 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(); StringBuilder sb = new StringBuilder();
for (String attribute : _attributes) { for (String attribute : this.attributes) {
sb.append(LanguageTag.SEP).append(attribute); sb.append(LanguageTag.SEP).append(attribute);
} }
for (Entry<String, String> keyword : _keywords.entrySet()) { for (Entry<String, String> keyword : this.keywords.entrySet()) {
String key = keyword.getKey(); String key = keyword.getKey();
String value = keyword.getValue(); String value = keyword.getValue();
...@@ -90,38 +83,46 @@ public class UnicodeLocaleExtension extends Extension { ...@@ -90,38 +83,46 @@ public class UnicodeLocaleExtension extends Extension {
sb.append(LanguageTag.SEP).append(value); sb.append(LanguageTag.SEP).append(value);
} }
} }
_value = sb.substring(1); // skip leading '-' setValue(sb.substring(1)); // skip leading '-'
} }
} }
public Set<String> getUnicodeLocaleAttributes() { public Set<String> getUnicodeLocaleAttributes() {
return Collections.unmodifiableSet(_attributes); if (attributes == Collections.EMPTY_SET) {
return attributes;
}
return Collections.unmodifiableSet(attributes);
} }
public Set<String> getUnicodeLocaleKeys() { public Set<String> getUnicodeLocaleKeys() {
return Collections.unmodifiableSet(_keywords.keySet()); if (keywords == Collections.EMPTY_MAP) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(keywords.keySet());
} }
public String getUnicodeLocaleType(String unicodeLocaleKey) { public String getUnicodeLocaleType(String unicodeLocaleKey) {
return _keywords.get(unicodeLocaleKey); return keywords.get(unicodeLocaleKey);
} }
public static boolean isSingletonChar(char c) { public static boolean isSingletonChar(char c) {
return (SINGLETON == AsciiUtil.toLower(c)); return (SINGLETON == LocaleUtils.toLower(c));
} }
public static boolean isAttribute(String s) { public static boolean isAttribute(String s) {
// 3*8alphanum // 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) { public static boolean isKey(String s) {
// 2alphanum // 2alphanum
return (s.length() == 2) && AsciiUtil.isAlphaNumericString(s); return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
} }
public static boolean isTypeSubtag(String s) { public static boolean isTypeSubtag(String s) {
// 3*8alphanum // 3*8alphanum
return (s.length() >= 3) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s); int len = s.length();
return (len >= 3) && (len <= 8) && LocaleUtils.isAlphaNumericString(s);
} }
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -33,8 +33,10 @@ import java.io.ObjectInputStream; ...@@ -33,8 +33,10 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar;
import java.util.IllformedLocaleException; import java.util.IllformedLocaleException;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
...@@ -43,8 +45,10 @@ import java.util.Set; ...@@ -43,8 +45,10 @@ import java.util.Set;
/** /**
* @test * @test
* @bug 6875847 6992272 7002320 7015500 7023613 * @bug 6875847 6992272 7002320 7015500 7023613 7032820 7033504
* @summary test API changes to Locale * @summary test API changes to Locale
* @compile LocaleEnhanceTest.java
* @run main/othervm -esa LocaleEnhanceTest
*/ */
public class LocaleEnhanceTest extends LocaleTestFmwk { public class LocaleEnhanceTest extends LocaleTestFmwk {
...@@ -593,6 +597,9 @@ public class LocaleEnhanceTest extends LocaleTestFmwk { ...@@ -593,6 +597,9 @@ public class LocaleEnhanceTest extends LocaleTestFmwk {
assertEquals("extension", "aa-00-bb-01", locale.getExtension('d')); assertEquals("extension", "aa-00-bb-01", locale.getExtension('d'));
assertEquals("extension c", "1234", locale.getExtension('c')); 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 // redundant Unicode locale keys in an extension are ignored
locale = Locale.forLanguageTag("und-u-aa-000-bb-001-bB-002-cc-003-c-1234"); 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)); assertEquals("Unicode keywords", "aa-000-bb-001-cc-003", locale.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
...@@ -1275,6 +1282,35 @@ public class LocaleEnhanceTest extends LocaleTestFmwk { ...@@ -1275,6 +1282,35 @@ public class LocaleEnhanceTest extends LocaleTestFmwk {
} }
} }
/*
* 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 /// utility asserts
/// ///
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册