1 /* 2 ******************************************************************************* 3 * Copyright (C) 2009-2010, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 package com.ibm.icu.impl.locale; 8 9 import java.util.Collections; 10 import java.util.Map; 11 import java.util.Map.Entry; 12 import java.util.Set; 13 import java.util.SortedMap; 14 import java.util.TreeMap; 15 import java.util.TreeSet; 16 17 import com.ibm.icu.impl.locale.InternalLocaleBuilder.CaseInsensitiveChar; 18 import com.ibm.icu.impl.locale.InternalLocaleBuilder.CaseInsensitiveString; 19 20 21 public class LocaleExtensions { 22 23 private SortedMap<Character, Extension> _map; 24 private String _id; 25 26 private static final SortedMap<Character, Extension> EMPTY_MAP = 27 Collections.unmodifiableSortedMap(new TreeMap<Character, Extension>()); 28 29 public static final LocaleExtensions EMPTY_EXTENSIONS; 30 public static final LocaleExtensions CALENDAR_JAPANESE; 31 public static final LocaleExtensions NUMBER_THAI; 32 33 static { 34 EMPTY_EXTENSIONS = new LocaleExtensions(); 35 EMPTY_EXTENSIONS._id = ""; 36 EMPTY_EXTENSIONS._map = EMPTY_MAP; 37 38 CALENDAR_JAPANESE = new LocaleExtensions(); 39 CALENDAR_JAPANESE._id = "u-ca-japanese"; 40 CALENDAR_JAPANESE._map = new TreeMap<Character, Extension>(); Character.valueOf(UnicodeLocaleExtension.SINGLETON)41 CALENDAR_JAPANESE._map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), UnicodeLocaleExtension.CA_JAPANESE); 42 43 NUMBER_THAI = new LocaleExtensions(); 44 NUMBER_THAI._id = "u-nu-thai"; 45 NUMBER_THAI._map = new TreeMap<Character, Extension>(); Character.valueOf(UnicodeLocaleExtension.SINGLETON)46 NUMBER_THAI._map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), UnicodeLocaleExtension.NU_THAI); 47 } 48 LocaleExtensions()49 private LocaleExtensions() { 50 } 51 52 /* 53 * Package local constructor, only used by InternalLocaleBuilder. 54 */ LocaleExtensions(Map<CaseInsensitiveChar, String> extensions, Set<CaseInsensitiveString> uattributes, Map<CaseInsensitiveString, String> ukeywords)55 LocaleExtensions(Map<CaseInsensitiveChar, String> extensions, 56 Set<CaseInsensitiveString> uattributes, Map<CaseInsensitiveString, String> ukeywords) { 57 boolean hasExtension = (extensions != null && extensions.size() > 0); 58 boolean hasUAttributes = (uattributes != null && uattributes.size() > 0); 59 boolean hasUKeywords = (ukeywords != null && ukeywords.size() > 0); 60 61 if (!hasExtension && !hasUAttributes && !hasUKeywords) { 62 _map = EMPTY_MAP; 63 _id = ""; 64 return; 65 } 66 67 // Build extension map 68 _map = new TreeMap<Character, Extension>(); 69 if (hasExtension) { 70 for (Entry<CaseInsensitiveChar, String> ext : extensions.entrySet()) { 71 char key = AsciiUtil.toLower(ext.getKey().value()); 72 String value = ext.getValue(); 73 74 if (LanguageTag.isPrivateusePrefixChar(key)) { 75 // we need to exclude special variant in privuateuse, e.g. "x-abc-lvariant-DEF" 76 value = InternalLocaleBuilder.removePrivateuseVariant(value); 77 if (value == null) { 78 continue; 79 } 80 } 81 82 Extension e = new Extension(key, AsciiUtil.toLowerString(value)); 83 _map.put(Character.valueOf(key), e); 84 } 85 } 86 87 if (hasUAttributes || hasUKeywords) { 88 TreeSet<String> uaset = null; 89 TreeMap<String, String> ukmap = null; 90 91 if (hasUAttributes) { 92 uaset = new TreeSet<String>(); 93 for (CaseInsensitiveString cis : uattributes) { 94 uaset.add(AsciiUtil.toLowerString(cis.value())); 95 } 96 } 97 98 if (hasUKeywords) { 99 ukmap = new TreeMap<String, String>(); 100 for (Entry<CaseInsensitiveString, String> kwd : ukeywords.entrySet()) { 101 String key = AsciiUtil.toLowerString(kwd.getKey().value()); 102 String type = AsciiUtil.toLowerString(kwd.getValue()); 103 ukmap.put(key, type); 104 } 105 } 106 107 UnicodeLocaleExtension ule = new UnicodeLocaleExtension(uaset, ukmap); 108 _map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), ule); 109 } 110 111 if (_map.size() == 0) { 112 // this could happen when only privuateuse with special variant 113 _map = EMPTY_MAP; 114 _id = ""; 115 } else { 116 _id = toID(_map); 117 } 118 } 119 getKeys()120 public Set<Character> getKeys() { 121 return Collections.unmodifiableSet(_map.keySet()); 122 } 123 getExtension(Character key)124 public Extension getExtension(Character key) { 125 return _map.get(Character.valueOf(AsciiUtil.toLower(key.charValue()))); 126 } 127 getExtensionValue(Character key)128 public String getExtensionValue(Character key) { 129 Extension ext = _map.get(Character.valueOf(AsciiUtil.toLower(key.charValue()))); 130 if (ext == null) { 131 return null; 132 } 133 return ext.getValue(); 134 } 135 getUnicodeLocaleAttributes()136 public Set<String> getUnicodeLocaleAttributes() { 137 Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); 138 if (ext == null) { 139 return Collections.emptySet(); 140 } 141 assert (ext instanceof UnicodeLocaleExtension); 142 return ((UnicodeLocaleExtension)ext).getUnicodeLocaleAttributes(); 143 } 144 getUnicodeLocaleKeys()145 public Set<String> getUnicodeLocaleKeys() { 146 Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); 147 if (ext == null) { 148 return Collections.emptySet(); 149 } 150 assert (ext instanceof UnicodeLocaleExtension); 151 return ((UnicodeLocaleExtension)ext).getUnicodeLocaleKeys(); 152 } 153 getUnicodeLocaleType(String unicodeLocaleKey)154 public String getUnicodeLocaleType(String unicodeLocaleKey) { 155 Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); 156 if (ext == null) { 157 return null; 158 } 159 assert (ext instanceof UnicodeLocaleExtension); 160 return ((UnicodeLocaleExtension)ext).getUnicodeLocaleType(AsciiUtil.toLowerString(unicodeLocaleKey)); 161 } 162 isEmpty()163 public boolean isEmpty() { 164 return _map.isEmpty(); 165 } 166 isValidKey(char c)167 public static boolean isValidKey(char c) { 168 return LanguageTag.isExtensionSingletonChar(c) || LanguageTag.isPrivateusePrefixChar(c); 169 } 170 isValidUnicodeLocaleKey(String ukey)171 public static boolean isValidUnicodeLocaleKey(String ukey) { 172 return UnicodeLocaleExtension.isKey(ukey); 173 } 174 toID(SortedMap<Character, Extension> map)175 private static String toID(SortedMap<Character, Extension> map) { 176 StringBuilder buf = new StringBuilder(); 177 Extension privuse = null; 178 for (Entry<Character, Extension> entry : map.entrySet()) { 179 char singleton = entry.getKey().charValue(); 180 Extension extension = entry.getValue(); 181 if (LanguageTag.isPrivateusePrefixChar(singleton)) { 182 privuse = extension; 183 } else { 184 if (buf.length() > 0) { 185 buf.append(LanguageTag.SEP); 186 } 187 buf.append(extension); 188 } 189 } 190 if (privuse != null) { 191 if (buf.length() > 0) { 192 buf.append(LanguageTag.SEP); 193 } 194 buf.append(privuse); 195 } 196 return buf.toString(); 197 } 198 199 toString()200 public String toString() { 201 return _id; 202 } 203 getID()204 public String getID() { 205 return _id; 206 } 207 hashCode()208 public int hashCode() { 209 return _id.hashCode(); 210 } 211 equals(Object other)212 public boolean equals(Object other) { 213 if (this == other) { 214 return true; 215 } 216 if (!(other instanceof LocaleExtensions)) { 217 return false; 218 } 219 return this._id.equals(((LocaleExtensions)other)._id); 220 } 221 } 222