Home | History | Annotate | Download | only in locale
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 2009-2010, International Business Machines Corporation and    *
      6  * others. All Rights Reserved.                                                *
      7  *******************************************************************************
      8  */
      9 
     10 package com.ibm.icu.impl.locale;
     11 
     12 
     13 public final class BaseLocale {
     14 
     15     private static final boolean JDKIMPL = false;
     16 
     17     public static final String SEP = "_";
     18 
     19     private static final Cache CACHE = new Cache();
     20     public static final BaseLocale ROOT = BaseLocale.getInstance("", "", "", "");
     21 
     22     private String _language = "";
     23     private String _script = "";
     24     private String _region = "";
     25     private String _variant = "";
     26 
     27     private transient volatile int _hash = 0;
     28 
     29     private BaseLocale(String language, String script, String region, String variant) {
     30         if (language != null) {
     31             _language = AsciiUtil.toLowerString(language).intern();
     32         }
     33         if (script != null) {
     34             _script = AsciiUtil.toTitleString(script).intern();
     35         }
     36         if (region != null) {
     37             _region = AsciiUtil.toUpperString(region).intern();
     38         }
     39         if (variant != null) {
     40             if (JDKIMPL) {
     41                 // preserve upper/lower cases
     42                 _variant = variant.intern();
     43             } else {
     44                 _variant = AsciiUtil.toUpperString(variant).intern();
     45             }
     46         }
     47     }
     48 
     49     public static BaseLocale getInstance(String language, String script, String region, String variant) {
     50         if (JDKIMPL) {
     51             // JDK uses deprecated ISO639.1 language codes for he, yi and id
     52             if (AsciiUtil.caseIgnoreMatch(language, "he")) {
     53                 language = "iw";
     54             } else if (AsciiUtil.caseIgnoreMatch(language, "yi")) {
     55                 language = "ji";
     56             } else if (AsciiUtil.caseIgnoreMatch(language, "id")) {
     57                 language = "in";
     58             }
     59         }
     60         Key key = new Key(language, script, region, variant);
     61         BaseLocale baseLocale = CACHE.get(key);
     62         return baseLocale;
     63     }
     64 
     65     public String getLanguage() {
     66         return _language;
     67     }
     68 
     69     public String getScript() {
     70         return _script;
     71     }
     72 
     73     public String getRegion() {
     74         return _region;
     75     }
     76 
     77     public String getVariant() {
     78         return _variant;
     79     }
     80 
     81     @Override
     82     public boolean equals(Object obj) {
     83         if (this == obj) {
     84             return true;
     85         }
     86         if (!(obj instanceof BaseLocale)) {
     87             return false;
     88         }
     89         BaseLocale other = (BaseLocale)obj;
     90         return hashCode() == other.hashCode()
     91                 && _language.equals(other._language)
     92                 && _script.equals(other._script)
     93                 && _region.equals(other._region)
     94                 && _variant.equals(other._variant);
     95     }
     96 
     97     @Override
     98     public String toString() {
     99         StringBuilder buf = new StringBuilder();
    100         if (_language.length() > 0) {
    101             buf.append("language=");
    102             buf.append(_language);
    103         }
    104         if (_script.length() > 0) {
    105             if (buf.length() > 0) {
    106                 buf.append(", ");
    107             }
    108             buf.append("script=");
    109             buf.append(_script);
    110         }
    111         if (_region.length() > 0) {
    112             if (buf.length() > 0) {
    113                 buf.append(", ");
    114             }
    115             buf.append("region=");
    116             buf.append(_region);
    117         }
    118         if (_variant.length() > 0) {
    119             if (buf.length() > 0) {
    120                 buf.append(", ");
    121             }
    122             buf.append("variant=");
    123             buf.append(_variant);
    124         }
    125         return buf.toString();
    126     }
    127 
    128     @Override
    129     public int hashCode() {
    130         int h = _hash;
    131         if (h == 0) {
    132             // Generating a hash value from language, script, region and variant
    133             for (int i = 0; i < _language.length(); i++) {
    134                 h = 31*h + _language.charAt(i);
    135             }
    136             for (int i = 0; i < _script.length(); i++) {
    137                 h = 31*h + _script.charAt(i);
    138             }
    139             for (int i = 0; i < _region.length(); i++) {
    140                 h = 31*h + _region.charAt(i);
    141             }
    142             for (int i = 0; i < _variant.length(); i++) {
    143                 h = 31*h + _variant.charAt(i);
    144             }
    145             _hash = h;
    146         }
    147         return h;
    148     }
    149 
    150     private static class Key implements Comparable<Key> {
    151         private String _lang = "";
    152         private String _scrt = "";
    153         private String _regn = "";
    154         private String _vart = "";
    155 
    156         private volatile int _hash; // Default to 0
    157 
    158         public Key(String language, String script, String region, String variant) {
    159             if (language != null) {
    160                 _lang = language;
    161             }
    162             if (script != null) {
    163                 _scrt = script;
    164             }
    165             if (region != null) {
    166                 _regn = region;
    167             }
    168             if (variant != null) {
    169                 _vart = variant;
    170             }
    171         }
    172 
    173         @Override
    174         public boolean equals(Object obj) {
    175             if (JDKIMPL) {
    176                 return (this == obj) ||
    177                         (obj instanceof Key)
    178                         && AsciiUtil.caseIgnoreMatch(((Key)obj)._lang, this._lang)
    179                         && AsciiUtil.caseIgnoreMatch(((Key)obj)._scrt, this._scrt)
    180                         && AsciiUtil.caseIgnoreMatch(((Key)obj)._regn, this._regn)
    181                         && ((Key)obj)._vart.equals(_vart); // variant is case sensitive in JDK!
    182             }
    183             return (this == obj) ||
    184                     (obj instanceof Key)
    185                     && AsciiUtil.caseIgnoreMatch(((Key)obj)._lang, this._lang)
    186                     && AsciiUtil.caseIgnoreMatch(((Key)obj)._scrt, this._scrt)
    187                     && AsciiUtil.caseIgnoreMatch(((Key)obj)._regn, this._regn)
    188                     && AsciiUtil.caseIgnoreMatch(((Key)obj)._vart, this._vart);
    189         }
    190 
    191         @Override
    192         public int compareTo(Key other) {
    193             int res = AsciiUtil.caseIgnoreCompare(this._lang, other._lang);
    194             if (res == 0) {
    195                 res = AsciiUtil.caseIgnoreCompare(this._scrt, other._scrt);
    196                 if (res == 0) {
    197                     res = AsciiUtil.caseIgnoreCompare(this._regn, other._regn);
    198                     if (res == 0) {
    199                         if (JDKIMPL) {
    200                             res = this._vart.compareTo(other._vart);
    201                         } else {
    202                             res = AsciiUtil.caseIgnoreCompare(this._vart, other._vart);
    203                         }
    204                     }
    205                 }
    206             }
    207             return res;
    208         }
    209 
    210         @Override
    211         public int hashCode() {
    212             int h = _hash;
    213             if (h == 0) {
    214                 // Generating a hash value from language, script, region and variant
    215                 for (int i = 0; i < _lang.length(); i++) {
    216                     h = 31*h + AsciiUtil.toLower(_lang.charAt(i));
    217                 }
    218                 for (int i = 0; i < _scrt.length(); i++) {
    219                     h = 31*h + AsciiUtil.toLower(_scrt.charAt(i));
    220                 }
    221                 for (int i = 0; i < _regn.length(); i++) {
    222                     h = 31*h + AsciiUtil.toLower(_regn.charAt(i));
    223                 }
    224                 for (int i = 0; i < _vart.length(); i++) {
    225                     if (JDKIMPL) {
    226                         h = 31*h + _vart.charAt(i);
    227                     } else {
    228                         h = 31*h + AsciiUtil.toLower(_vart.charAt(i));
    229                     }
    230                 }
    231                 _hash = h;
    232             }
    233             return h;
    234         }
    235 
    236         public static Key normalize(Key key) {
    237             String lang = AsciiUtil.toLowerString(key._lang).intern();
    238             String scrt = AsciiUtil.toTitleString(key._scrt).intern();
    239             String regn = AsciiUtil.toUpperString(key._regn).intern();
    240             String vart;
    241             if (JDKIMPL) {
    242                 // preserve upper/lower cases
    243                 vart = key._vart.intern();
    244             } else {
    245                 vart = AsciiUtil.toUpperString(key._vart).intern();
    246             }
    247             return new Key(lang, scrt, regn, vart);
    248         }
    249     }
    250 
    251     private static class Cache extends LocaleObjectCache<Key, BaseLocale> {
    252 
    253         public Cache() {
    254         }
    255 
    256         @Override
    257         protected Key normalizeKey(Key key) {
    258             return Key.normalize(key);
    259         }
    260 
    261         @Override
    262         protected BaseLocale createObject(Key key) {
    263             return new BaseLocale(key._lang, key._scrt, key._regn, key._vart);
    264         }
    265 
    266     }
    267 }
    268