1 /* 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 ******************************************************************************* 28 * Copyright (C) 2009-2010, International Business Machines Corporation and * 29 * others. All Rights Reserved. * 30 ******************************************************************************* 31 */ 32 33 package sun.util.locale; 34 import java.lang.ref.SoftReference; 35 36 37 public final class BaseLocale { 38 39 public static final String SEP = "_"; 40 41 private static final Cache CACHE = new Cache(); 42 43 private final String language; 44 private final String script; 45 private final String region; 46 private final String variant; 47 48 private volatile int hash = 0; 49 50 // This method must be called only when creating the Locale.* constants. BaseLocale(String language, String region)51 private BaseLocale(String language, String region) { 52 this.language = language; 53 this.script = ""; 54 this.region = region; 55 this.variant = ""; 56 } 57 BaseLocale(String language, String script, String region, String variant)58 private BaseLocale(String language, String script, String region, String variant) { 59 this.language = (language != null) ? LocaleUtils.toLowerString(language).intern() : ""; 60 this.script = (script != null) ? LocaleUtils.toTitleString(script).intern() : ""; 61 this.region = (region != null) ? LocaleUtils.toUpperString(region).intern() : ""; 62 this.variant = (variant != null) ? variant.intern() : ""; 63 } 64 65 // Called for creating the Locale.* constants. No argument 66 // validation is performed. createInstance(String language, String region)67 public static BaseLocale createInstance(String language, String region) { 68 BaseLocale base = new BaseLocale(language, region); 69 CACHE.put(new Key(language, region), base); 70 return base; 71 } 72 getInstance(String language, String script, String region, String variant)73 public static BaseLocale getInstance(String language, String script, 74 String region, String variant) { 75 // JDK uses deprecated ISO639.1 language codes for he, yi and id 76 if (language != null) { 77 if (LocaleUtils.caseIgnoreMatch(language, "he")) { 78 language = "iw"; 79 } else if (LocaleUtils.caseIgnoreMatch(language, "yi")) { 80 language = "ji"; 81 } else if (LocaleUtils.caseIgnoreMatch(language, "id")) { 82 language = "in"; 83 } 84 } 85 86 Key key = new Key(language, script, region, variant); 87 BaseLocale baseLocale = CACHE.get(key); 88 return baseLocale; 89 } 90 getLanguage()91 public String getLanguage() { 92 return language; 93 } 94 getScript()95 public String getScript() { 96 return script; 97 } 98 getRegion()99 public String getRegion() { 100 return region; 101 } 102 getVariant()103 public String getVariant() { 104 return variant; 105 } 106 107 @Override equals(Object obj)108 public boolean equals(Object obj) { 109 if (this == obj) { 110 return true; 111 } 112 if (!(obj instanceof BaseLocale)) { 113 return false; 114 } 115 BaseLocale other = (BaseLocale)obj; 116 return language == other.language 117 && script == other.script 118 && region == other.region 119 && variant == other.variant; 120 } 121 122 @Override toString()123 public String toString() { 124 StringBuilder buf = new StringBuilder(); 125 if (language.length() > 0) { 126 buf.append("language="); 127 buf.append(language); 128 } 129 if (script.length() > 0) { 130 if (buf.length() > 0) { 131 buf.append(", "); 132 } 133 buf.append("script="); 134 buf.append(script); 135 } 136 if (region.length() > 0) { 137 if (buf.length() > 0) { 138 buf.append(", "); 139 } 140 buf.append("region="); 141 buf.append(region); 142 } 143 if (variant.length() > 0) { 144 if (buf.length() > 0) { 145 buf.append(", "); 146 } 147 buf.append("variant="); 148 buf.append(variant); 149 } 150 return buf.toString(); 151 } 152 153 @Override hashCode()154 public int hashCode() { 155 int h = hash; 156 if (h == 0) { 157 // Generating a hash value from language, script, region and variant 158 h = language.hashCode(); 159 h = 31 * h + script.hashCode(); 160 h = 31 * h + region.hashCode(); 161 h = 31 * h + variant.hashCode(); 162 hash = h; 163 } 164 return h; 165 } 166 167 private static final class Key { 168 private final SoftReference<String> lang; 169 private final SoftReference<String> scrt; 170 private final SoftReference<String> regn; 171 private final SoftReference<String> vart; 172 private final boolean normalized; 173 private final int hash; 174 175 /** 176 * Creates a Key. language and region must be normalized 177 * (intern'ed in the proper case). 178 */ Key(String language, String region)179 private Key(String language, String region) { 180 assert language.intern() == language 181 && region.intern() == region; 182 183 lang = new SoftReference(language); 184 scrt = new SoftReference(""); 185 regn = new SoftReference(region); 186 vart = new SoftReference(""); 187 this.normalized = true; 188 189 int h = language.hashCode(); 190 if (region != "") { 191 int len = region.length(); 192 for (int i = 0; i < len; i++) { 193 h = 31 * h + LocaleUtils.toLower(region.charAt(i)); 194 } 195 } 196 hash = h; 197 } 198 Key(String language, String script, String region, String variant)199 public Key(String language, String script, String region, String variant) { 200 this(language, script, region, variant, false); 201 } 202 Key(String language, String script, String region, String variant, boolean normalized)203 private Key(String language, String script, String region, 204 String variant, boolean normalized) { 205 int h = 0; 206 if (language != null) { 207 lang = new SoftReference(language); 208 int len = language.length(); 209 for (int i = 0; i < len; i++) { 210 h = 31*h + LocaleUtils.toLower(language.charAt(i)); 211 } 212 } else { 213 lang = new SoftReference(""); 214 } 215 if (script != null) { 216 scrt = new SoftReference(script); 217 int len = script.length(); 218 for (int i = 0; i < len; i++) { 219 h = 31*h + LocaleUtils.toLower(script.charAt(i)); 220 } 221 } else { 222 scrt = new SoftReference(""); 223 } 224 if (region != null) { 225 regn = new SoftReference(region); 226 int len = region.length(); 227 for (int i = 0; i < len; i++) { 228 h = 31*h + LocaleUtils.toLower(region.charAt(i)); 229 } 230 } else { 231 regn = new SoftReference(""); 232 } 233 if (variant != null) { 234 vart = new SoftReference(variant); 235 int len = variant.length(); 236 for (int i = 0; i < len; i++) { 237 h = 31*h + variant.charAt(i); 238 } 239 } else { 240 vart = new SoftReference(""); 241 } 242 hash = h; 243 this.normalized = normalized; 244 } 245 246 @Override equals(Object obj)247 public boolean equals(Object obj) { 248 if (this == obj) { 249 return true; 250 } 251 252 if (obj instanceof Key && this.hash == ((Key)obj).hash) { 253 String tl = this.lang.get(); 254 String ol = ((Key)obj).lang.get(); 255 if (tl != null && ol != null && 256 LocaleUtils.caseIgnoreMatch(ol, tl)) { 257 String ts = this.scrt.get(); 258 String os = ((Key)obj).scrt.get(); 259 if (ts != null && os != null && 260 LocaleUtils.caseIgnoreMatch(os, ts)) { 261 String tr = this.regn.get(); 262 String or = ((Key)obj).regn.get(); 263 if (tr != null && or != null && 264 LocaleUtils.caseIgnoreMatch(or, tr)) { 265 String tv = this.vart.get(); 266 String ov = ((Key)obj).vart.get(); 267 return (ov != null && ov.equals(tv)); 268 } 269 } 270 } 271 } 272 return false; 273 } 274 275 @Override hashCode()276 public int hashCode() { 277 return hash; 278 } 279 normalize(Key key)280 public static Key normalize(Key key) { 281 if (key.normalized) { 282 return key; 283 } 284 285 String lang = LocaleUtils.toLowerString(key.lang.get()).intern(); 286 String scrt = LocaleUtils.toTitleString(key.scrt.get()).intern(); 287 String regn = LocaleUtils.toUpperString(key.regn.get()).intern(); 288 String vart = key.vart.get().intern(); // preserve upper/lower cases 289 290 return new Key(lang, scrt, regn, vart, true); 291 } 292 } 293 294 private static class Cache extends LocaleObjectCache<Key, BaseLocale> { 295 Cache()296 public Cache() { 297 } 298 299 @Override normalizeKey(Key key)300 protected Key normalizeKey(Key key) { 301 assert key.lang.get() != null && 302 key.scrt.get() != null && 303 key.regn.get() != null && 304 key.vart.get() != null; 305 306 return Key.normalize(key); 307 } 308 309 @Override createObject(Key key)310 protected BaseLocale createObject(Key key) { 311 return new BaseLocale(key.lang.get(), key.scrt.get(), 312 key.regn.get(), key.vart.get()); 313 } 314 } 315 } 316