jdk/src/share/classes/sun/util/locale/BaseLocale.java
changeset 9224 75c0420badef
parent 6655 b4130d85e450
equal deleted inserted replaced
9223:d331b7996fc3 9224:75c0420badef
     1 /*
     1 /*
     2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
     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.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    36 public final class BaseLocale {
    36 public final class BaseLocale {
    37 
    37 
    38     public static final String SEP = "_";
    38     public static final String SEP = "_";
    39 
    39 
    40     private static final Cache CACHE = new Cache();
    40     private static final Cache CACHE = new Cache();
    41     public static final BaseLocale ROOT = BaseLocale.getInstance("", "", "", "");
    41 
    42 
    42     private final String language;
    43     private String _language = "";
    43     private final String script;
    44     private String _script = "";
    44     private final String region;
    45     private String _region = "";
    45     private final String variant;
    46     private String _variant = "";
    46 
    47 
    47     private volatile int hash = 0;
    48     private transient volatile int _hash = 0;
    48 
       
    49     // This method must be called only when creating the Locale.* constants.
       
    50     private BaseLocale(String language, String region) {
       
    51         this.language = language;
       
    52         this.script = "";
       
    53         this.region = region;
       
    54         this.variant = "";
       
    55     }
    49 
    56 
    50     private BaseLocale(String language, String script, String region, String variant) {
    57     private BaseLocale(String language, String script, String region, String variant) {
    51         if (language != null) {
    58         this.language = (language != null) ? LocaleUtils.toLowerString(language).intern() : "";
    52             _language = AsciiUtil.toLowerString(language).intern();
    59         this.script = (script != null) ? LocaleUtils.toTitleString(script).intern() : "";
    53         }
    60         this.region = (region != null) ? LocaleUtils.toUpperString(region).intern() : "";
    54         if (script != null) {
    61         this.variant = (variant != null) ? variant.intern() : "";
    55             _script = AsciiUtil.toTitleString(script).intern();
    62     }
    56         }
    63 
    57         if (region != null) {
    64     // Called for creating the Locale.* constants. No argument
    58             _region = AsciiUtil.toUpperString(region).intern();
    65     // validation is performed.
    59         }
    66     public static BaseLocale createInstance(String language, String region) {
    60         if (variant != null) {
    67         BaseLocale base = new BaseLocale(language, region);
    61             _variant = variant.intern();
    68         CACHE.put(new Key(language, region), base);
    62         }
    69         return base;
    63     }
    70     }
    64 
    71 
    65     public static BaseLocale getInstance(String language, String script, String region, String variant) {
    72     public static BaseLocale getInstance(String language, String script,
       
    73                                          String region, String variant) {
    66         // JDK uses deprecated ISO639.1 language codes for he, yi and id
    74         // JDK uses deprecated ISO639.1 language codes for he, yi and id
    67         if (language != null) {
    75         if (language != null) {
    68             if (AsciiUtil.caseIgnoreMatch(language, "he")) {
    76             if (LocaleUtils.caseIgnoreMatch(language, "he")) {
    69                 language = "iw";
    77                 language = "iw";
    70             } else if (AsciiUtil.caseIgnoreMatch(language, "yi")) {
    78             } else if (LocaleUtils.caseIgnoreMatch(language, "yi")) {
    71                 language = "ji";
    79                 language = "ji";
    72             } else if (AsciiUtil.caseIgnoreMatch(language, "id")) {
    80             } else if (LocaleUtils.caseIgnoreMatch(language, "id")) {
    73                 language = "in";
    81                 language = "in";
    74             }
    82             }
    75         }
    83         }
    76 
    84 
    77         Key key = new Key(language, script, region, variant);
    85         Key key = new Key(language, script, region, variant);
    78         BaseLocale baseLocale = CACHE.get(key);
    86         BaseLocale baseLocale = CACHE.get(key);
    79         return baseLocale;
    87         return baseLocale;
    80     }
    88     }
    81 
    89 
    82     public String getLanguage() {
    90     public String getLanguage() {
    83         return _language;
    91         return language;
    84     }
    92     }
    85 
    93 
    86     public String getScript() {
    94     public String getScript() {
    87         return _script;
    95         return script;
    88     }
    96     }
    89 
    97 
    90     public String getRegion() {
    98     public String getRegion() {
    91         return _region;
    99         return region;
    92     }
   100     }
    93 
   101 
    94     public String getVariant() {
   102     public String getVariant() {
    95         return _variant;
   103         return variant;
    96     }
   104     }
    97 
   105 
       
   106     @Override
    98     public boolean equals(Object obj) {
   107     public boolean equals(Object obj) {
    99         if (this == obj) {
   108         if (this == obj) {
   100             return true;
   109             return true;
   101         }
   110         }
   102         if (!(obj instanceof BaseLocale)) {
   111         if (!(obj instanceof BaseLocale)) {
   103             return false;
   112             return false;
   104         }
   113         }
   105         BaseLocale other = (BaseLocale)obj;
   114         BaseLocale other = (BaseLocale)obj;
   106         return hashCode() == other.hashCode()
   115         return language == other.language
   107                 && _language.equals(other._language)
   116                && script == other.script
   108                 && _script.equals(other._script)
   117                && region == other.region
   109                 && _region.equals(other._region)
   118                && variant == other.variant;
   110                 && _variant.equals(other._variant);
   119     }
   111     }
   120 
   112 
   121     @Override
   113     public String toString() {
   122     public String toString() {
   114         StringBuilder buf = new StringBuilder();
   123         StringBuilder buf = new StringBuilder();
   115         if (_language.length() > 0) {
   124         if (language.length() > 0) {
   116             buf.append("language=");
   125             buf.append("language=");
   117             buf.append(_language);
   126             buf.append(language);
   118         }
   127         }
   119         if (_script.length() > 0) {
   128         if (script.length() > 0) {
   120             if (buf.length() > 0) {
   129             if (buf.length() > 0) {
   121                 buf.append(", ");
   130                 buf.append(", ");
   122             }
   131             }
   123             buf.append("script=");
   132             buf.append("script=");
   124             buf.append(_script);
   133             buf.append(script);
   125         }
   134         }
   126         if (_region.length() > 0) {
   135         if (region.length() > 0) {
   127             if (buf.length() > 0) {
   136             if (buf.length() > 0) {
   128                 buf.append(", ");
   137                 buf.append(", ");
   129             }
   138             }
   130             buf.append("region=");
   139             buf.append("region=");
   131             buf.append(_region);
   140             buf.append(region);
   132         }
   141         }
   133         if (_variant.length() > 0) {
   142         if (variant.length() > 0) {
   134             if (buf.length() > 0) {
   143             if (buf.length() > 0) {
   135                 buf.append(", ");
   144                 buf.append(", ");
   136             }
   145             }
   137             buf.append("variant=");
   146             buf.append("variant=");
   138             buf.append(_variant);
   147             buf.append(variant);
   139         }
   148         }
   140         return buf.toString();
   149         return buf.toString();
   141     }
   150     }
   142 
   151 
       
   152     @Override
   143     public int hashCode() {
   153     public int hashCode() {
   144         int h = _hash;
   154         int h = hash;
   145         if (h == 0) {
   155         if (h == 0) {
   146             // Generating a hash value from language, script, region and variant
   156             // Generating a hash value from language, script, region and variant
   147             for (int i = 0; i < _language.length(); i++) {
   157             h = language.hashCode();
   148                 h = 31*h + _language.charAt(i);
   158             h = 31 * h + script.hashCode();
   149             }
   159             h = 31 * h + region.hashCode();
   150             for (int i = 0; i < _script.length(); i++) {
   160             h = 31 * h + variant.hashCode();
   151                 h = 31*h + _script.charAt(i);
   161             hash = h;
   152             }
       
   153             for (int i = 0; i < _region.length(); i++) {
       
   154                 h = 31*h + _region.charAt(i);
       
   155             }
       
   156             for (int i = 0; i < _variant.length(); i++) {
       
   157                 h = 31*h + _variant.charAt(i);
       
   158             }
       
   159             _hash = h;
       
   160         }
   162         }
   161         return h;
   163         return h;
   162     }
   164     }
   163 
   165 
   164     private static class Key implements Comparable<Key> {
   166     private static final class Key implements Comparable<Key> {
   165         private String _lang = "";
   167         private final String lang;
   166         private String _scrt = "";
   168         private final String scrt;
   167         private String _regn = "";
   169         private final String regn;
   168         private String _vart = "";
   170         private final String vart;
   169 
   171         private final boolean normalized;
   170         private volatile int _hash; // Default to 0
   172         private final int hash;
       
   173 
       
   174         /**
       
   175          * Creates a Key. language and region must be normalized
       
   176          * (intern'ed in the proper case).
       
   177          */
       
   178         private Key(String language, String region) {
       
   179             assert language.intern() == language
       
   180                    && region.intern() == region;
       
   181 
       
   182             lang = language;
       
   183             scrt = "";
       
   184             regn = region;
       
   185             vart = "";
       
   186             this.normalized = true;
       
   187 
       
   188             int h = language.hashCode();
       
   189             if (region != "") {
       
   190                 int len = region.length();
       
   191                 for (int i = 0; i < len; i++) {
       
   192                     h = 31 * h + LocaleUtils.toLower(region.charAt(i));
       
   193                 }
       
   194             }
       
   195             hash = h;
       
   196         }
   171 
   197 
   172         public Key(String language, String script, String region, String variant) {
   198         public Key(String language, String script, String region, String variant) {
       
   199             this(language, script, region, variant, false);
       
   200         }
       
   201 
       
   202         private Key(String language, String script, String region,
       
   203                     String variant, boolean normalized) {
       
   204             int h = 0;
   173             if (language != null) {
   205             if (language != null) {
   174                 _lang = language;
   206                 lang = language;
       
   207                 int len = language.length();
       
   208                 for (int i = 0; i < len; i++) {
       
   209                     h = 31*h + LocaleUtils.toLower(language.charAt(i));
       
   210                 }
       
   211             } else {
       
   212                 lang = "";
   175             }
   213             }
   176             if (script != null) {
   214             if (script != null) {
   177                 _scrt = script;
   215                 scrt = script;
       
   216                 int len = script.length();
       
   217                 for (int i = 0; i < len; i++) {
       
   218                     h = 31*h + LocaleUtils.toLower(script.charAt(i));
       
   219                 }
       
   220             } else {
       
   221                 scrt = "";
   178             }
   222             }
   179             if (region != null) {
   223             if (region != null) {
   180                 _regn = region;
   224                 regn = region;
       
   225                 int len = region.length();
       
   226                 for (int i = 0; i < len; i++) {
       
   227                     h = 31*h + LocaleUtils.toLower(region.charAt(i));
       
   228                 }
       
   229             } else {
       
   230                 regn = "";
   181             }
   231             }
   182             if (variant != null) {
   232             if (variant != null) {
   183                 _vart = variant;
   233                 vart = variant;
   184             }
   234                 int len = variant.length();
   185         }
   235                 for (int i = 0; i < len; i++) {
   186 
   236                     h = 31*h + variant.charAt(i);
       
   237                 }
       
   238             } else {
       
   239                 vart = "";
       
   240             }
       
   241             hash = h;
       
   242             this.normalized = normalized;
       
   243         }
       
   244 
       
   245         @Override
   187         public boolean equals(Object obj) {
   246         public boolean equals(Object obj) {
   188             return (this == obj) ||
   247             return (this == obj) ||
   189                     (obj instanceof Key)
   248                     (obj instanceof Key)
   190                     && AsciiUtil.caseIgnoreMatch(((Key)obj)._lang, this._lang)
   249                     && this.hash == ((Key)obj).hash
   191                     && AsciiUtil.caseIgnoreMatch(((Key)obj)._scrt, this._scrt)
   250                     && LocaleUtils.caseIgnoreMatch(((Key)obj).lang, this.lang)
   192                     && AsciiUtil.caseIgnoreMatch(((Key)obj)._regn, this._regn)
   251                     && LocaleUtils.caseIgnoreMatch(((Key)obj).scrt, this.scrt)
   193                     && ((Key)obj)._vart.equals(_vart); // variant is case sensitive in JDK!
   252                     && LocaleUtils.caseIgnoreMatch(((Key)obj).regn, this.regn)
   194         }
   253                     && ((Key)obj).vart.equals(vart); // variant is case sensitive in JDK!
   195 
   254         }
       
   255 
       
   256         @Override
   196         public int compareTo(Key other) {
   257         public int compareTo(Key other) {
   197             int res = AsciiUtil.caseIgnoreCompare(this._lang, other._lang);
   258             int res = LocaleUtils.caseIgnoreCompare(this.lang, other.lang);
   198             if (res == 0) {
   259             if (res == 0) {
   199                 res = AsciiUtil.caseIgnoreCompare(this._scrt, other._scrt);
   260                 res = LocaleUtils.caseIgnoreCompare(this.scrt, other.scrt);
   200                 if (res == 0) {
   261                 if (res == 0) {
   201                     res = AsciiUtil.caseIgnoreCompare(this._regn, other._regn);
   262                     res = LocaleUtils.caseIgnoreCompare(this.regn, other.regn);
   202                     if (res == 0) {
   263                     if (res == 0) {
   203                         res = this._vart.compareTo(other._vart);
   264                         res = this.vart.compareTo(other.vart);
   204                     }
   265                     }
   205                 }
   266                 }
   206             }
   267             }
   207             return res;
   268             return res;
   208         }
   269         }
   209 
   270 
       
   271         @Override
   210         public int hashCode() {
   272         public int hashCode() {
   211             int h = _hash;
   273             return hash;
   212             if (h == 0) {
       
   213                 // Generating a hash value from language, script, region and variant
       
   214                 for (int i = 0; i < _lang.length(); i++) {
       
   215                     h = 31*h + AsciiUtil.toLower(_lang.charAt(i));
       
   216                 }
       
   217                 for (int i = 0; i < _scrt.length(); i++) {
       
   218                     h = 31*h + AsciiUtil.toLower(_scrt.charAt(i));
       
   219                 }
       
   220                 for (int i = 0; i < _regn.length(); i++) {
       
   221                     h = 31*h + AsciiUtil.toLower(_regn.charAt(i));
       
   222                 }
       
   223                 for (int i = 0; i < _vart.length(); i++) {
       
   224                     h = 31*h + _vart.charAt(i);
       
   225                 }
       
   226                 _hash = h;
       
   227             }
       
   228             return h;
       
   229         }
   274         }
   230 
   275 
   231         public static Key normalize(Key key) {
   276         public static Key normalize(Key key) {
   232             String lang = AsciiUtil.toLowerString(key._lang).intern();
   277             if (key.normalized) {
   233             String scrt = AsciiUtil.toTitleString(key._scrt).intern();
   278                 return key;
   234             String regn = AsciiUtil.toUpperString(key._regn).intern();
   279             }
   235             String vart = key._vart.intern(); // preserve upper/lower cases
   280 
   236 
   281             String lang = LocaleUtils.toLowerString(key.lang).intern();
   237             return new Key(lang, scrt, regn, vart);
   282             String scrt = LocaleUtils.toTitleString(key.scrt).intern();
       
   283             String regn = LocaleUtils.toUpperString(key.regn).intern();
       
   284             String vart = key.vart.intern(); // preserve upper/lower cases
       
   285 
       
   286             return new Key(lang, scrt, regn, vart, true);
   238         }
   287         }
   239     }
   288     }
   240 
   289 
   241     private static class Cache extends LocaleObjectCache<Key, BaseLocale> {
   290     private static class Cache extends LocaleObjectCache<Key, BaseLocale> {
   242 
   291 
   243         public Cache() {
   292         public Cache() {
   244         }
   293         }
   245 
   294 
       
   295         @Override
   246         protected Key normalizeKey(Key key) {
   296         protected Key normalizeKey(Key key) {
   247             return Key.normalize(key);
   297             return Key.normalize(key);
   248         }
   298         }
   249 
   299 
       
   300         @Override
   250         protected BaseLocale createObject(Key key) {
   301         protected BaseLocale createObject(Key key) {
   251             return new BaseLocale(key._lang, key._scrt, key._regn, key._vart);
   302             return new BaseLocale(key.lang, key.scrt, key.regn, key.vart);
   252         }
   303         }
   253 
       
   254     }
   304     }
   255 }
   305 }