1 /* 2 * Copyright (c) 1998, 2006, 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 package sun.io; 27 28 import java.io.UnsupportedEncodingException; 29 import java.lang.ref.SoftReference; 30 import java.util.Properties; 31 32 /** 33 * Package-private utility class that caches the default converter classes and 34 * provides other logic common to both the ByteToCharConverter and 35 * CharToByteConverter classes. 36 * 37 * @author Mark Reinhold 38 * @since 1.2 39 * 40 * @deprecated Replaced by {@link java.nio.charset}. THIS API WILL BE 41 * REMOVED IN J2SE 1.6. 42 */ 43 @Deprecated 44 public class Converters { 45 46 private Converters() { } /* To prevent instantiation */ 47 48 /* Lock for all static fields in this class */ 49 private static Object lock = Converters.class; 50 51 /* Cached values of system properties */ 52 private static String converterPackageName = null; /* file.encoding.pkg */ 53 private static String defaultEncoding = null; /* file.encoding */ 54 55 /* Converter type constants and names */ 56 public static final int BYTE_TO_CHAR = 0; 57 public static final int CHAR_TO_BYTE = 1; 58 private static final String[] converterPrefix = { "ByteToChar", 59 "CharToByte" }; 60 61 62 // -- Converter class cache -- 63 64 private static final int CACHE_SIZE = 3; 65 66 /* For the default charset, whatever it turns out to be */ 67 private static final Object DEFAULT_NAME = new Object(); 68 69 /* Cached converter classes, CACHE_SIZE per converter type. Each cache 70 * entry is a soft reference to a two-object array; the first element of 71 * the array is the converter class, the second is an object (typically a 72 * string) representing the encoding name that was used to request the 73 * converter, e.g., 74 * 75 * ((Object[])classCache[CHAR_TO_BYTE][i].get())[0] 76 * 77 * will be a CharToByteConverter and 78 * 79 * ((Object[])classCache[CHAR_TO_BYTE][i].get())[1] 80 * 81 * will be the string encoding name used to request it, assuming that cache 82 * entry i is valid. 83 * 84 * Ordinarily we'd do this with a private static utility class, but since 85 * this code can be involved in the startup sequence it's important to keep 86 * the footprint down. 87 */ 88 @SuppressWarnings("unchecked") 89 private static SoftReference<Object[]>[][] classCache 90 = (SoftReference<Object[]>[][]) new SoftReference<?>[][] { 91 new SoftReference<?>[CACHE_SIZE], 92 new SoftReference<?>[CACHE_SIZE] 93 }; 94 95 private static void moveToFront(Object[] oa, int i) { 96 Object ob = oa[i]; 97 for (int j = i; j > 0; j--) 98 oa[j] = oa[j - 1]; 99 oa[0] = ob; 100 } 101 102 private static Class<?> cache(int type, Object encoding) { 103 SoftReference<Object[]>[] srs = classCache[type]; 104 for (int i = 0; i < CACHE_SIZE; i++) { 105 SoftReference<Object[]> sr = srs[i]; 106 if (sr == null) 107 continue; 108 Object[] oa = sr.get(); 109 if (oa == null) { 110 srs[i] = null; 111 continue; 112 } 113 if (oa[1].equals(encoding)) { 114 moveToFront(srs, i); 115 return (Class<?>)oa[0]; 116 } 117 } 118 return null; 119 } 120 121 private static Class<?> cache(int type, Object encoding, Class<?> c) { 122 SoftReference<Object[]>[] srs = classCache[type]; 123 srs[CACHE_SIZE - 1] = new SoftReference<>(new Object[] { c, encoding }); 124 moveToFront(srs, CACHE_SIZE - 1); 125 return c; 126 } 127 128 /* Used to avoid doing expensive charset lookups for charsets that are not 129 * yet directly supported by NIO. 130 */ 131 public static boolean isCached(int type, String encoding) { 132 synchronized (lock) { 133 SoftReference<Object[]>[] srs = classCache[type]; 134 for (int i = 0; i < CACHE_SIZE; i++) { 135 SoftReference<Object[]> sr = srs[i]; 136 if (sr == null) 137 continue; 138 Object[] oa = sr.get(); 139 if (oa == null) { 140 srs[i] = null; 141 continue; 142 } 143 if (oa[1].equals(encoding)) 144 return true; 145 } 146 return false; 147 } 148 } 149 150 151 152 /** Get the name of the converter package */ 153 private static String getConverterPackageName() { 154 String cp = converterPackageName; 155 if (cp != null) return cp; 156 java.security.PrivilegedAction<String> pa = 157 new sun.security.action.GetPropertyAction("file.encoding.pkg"); 158 cp = java.security.AccessController.doPrivileged(pa); 159 if (cp != null) { 160 /* Property is set, so take it as the true converter package */ 161 converterPackageName = cp; 162 } else { 163 /* Fall back to sun.io */ 164 cp = "sun.io"; 165 } 166 return cp; 167 } 168 169 public static String getDefaultEncodingName() { 170 synchronized (lock) { 171 if (defaultEncoding == null) { 172 java.security.PrivilegedAction<String> pa = 173 new sun.security.action.GetPropertyAction("file.encoding"); 174 defaultEncoding = java.security.AccessController.doPrivileged(pa); 175 } 176 } 177 return defaultEncoding; 178 } 179 180 public static void resetDefaultEncodingName() { 181 // This method should only be called during VM initialization. 182 if (sun.misc.VM.isBooted()) 183 return; 184 185 synchronized (lock) { 186 defaultEncoding = "ISO-8859-1"; 187 Properties p = System.getProperties(); 188 p.setProperty("file.encoding", defaultEncoding); 189 System.setProperties(p); 190 } 191 } 192 193 /** 194 * Get the class that implements the given type of converter for the named 195 * encoding, or throw an UnsupportedEncodingException if no such class can 196 * be found 197 */ 198 private static Class<?> getConverterClass(int type, String encoding) 199 throws UnsupportedEncodingException 200 { 201 String enc = null; 202 203 /* "ISO8859_1" is the canonical name for the ISO-Latin-1 encoding. 204 Native code in the JDK commonly uses the alias "8859_1" instead of 205 "ISO8859_1". We hardwire this alias here in order to avoid loading 206 the full alias table just for this case. */ 207 if (!encoding.equals("ISO8859_1")) { 208 if (encoding.equals("8859_1")) { 209 enc = "ISO8859_1"; 210 /* 211 * On Solaris with nl_langinfo() called in GetJavaProperties(): 212 * 213 * locale undefined -> NULL -> hardcoded default 214 * "C" locale -> "" -> hardcoded default (on 2.6) 215 * "C" locale -> "646" (on 2.7) 216 * "en_US" locale -> "ISO8859-1" 217 * "en_GB" locale -> "ISO8859-1" (on 2.7) 218 * "en_UK" locale -> "ISO8859-1" (on 2.6) 219 */ 220 } else if (encoding.equals("ISO8859-1")) { 221 enc = "ISO8859_1"; 222 } else if (encoding.equals("646")) { 223 enc = "ASCII"; 224 } else { 225 enc = CharacterEncoding.aliasName(encoding); 226 } 227 } 228 if (enc == null) { 229 enc = encoding; 230 } 231 232 try { 233 return Class.forName(getConverterPackageName() 234 + "." + converterPrefix[type] + enc); 235 } catch(ClassNotFoundException e) { 236 throw new UnsupportedEncodingException(enc); 237 } 238 239 } 240 241 /** 242 * Instantiate the given converter class, or throw an 243 * UnsupportedEncodingException if it cannot be instantiated 244 */ 245 private static Object newConverter(String enc, Class<?> c) 246 throws UnsupportedEncodingException 247 { 248 try { 249 return c.newInstance(); 250 } catch(InstantiationException e) { 251 throw new UnsupportedEncodingException(enc); 252 } catch(IllegalAccessException e) { 253 throw new UnsupportedEncodingException(enc); 254 } 255 } 256 257 /** 258 * Create a converter object that implements the given type of converter 259 * for the given encoding, or throw an UnsupportedEncodingException if no 260 * appropriate converter class can be found and instantiated 261 */ 262 static Object newConverter(int type, String enc) 263 throws UnsupportedEncodingException 264 { 265 Class<?> c; 266 synchronized (lock) { 267 c = cache(type, enc); 268 if (c == null) { 269 c = getConverterClass(type, enc); 270 if (!c.getName().equals("sun.io.CharToByteUTF8")) 271 cache(type, enc, c); 272 } 273 } 274 return newConverter(enc, c); 275 } 276 277 /** 278 * Find the class that implements the given type of converter for the 279 * default encoding. If the default encoding cannot be determined or is 280 * not yet defined, return a class that implements the fallback default 281 * encoding, which is just ISO 8859-1. 282 */ 283 private static Class<?> getDefaultConverterClass(int type) { 284 boolean fillCache = false; 285 Class<?> c; 286 287 /* First check the class cache */ 288 c = cache(type, DEFAULT_NAME); 289 if (c != null) 290 return c; 291 292 /* Determine the encoding name */ 293 String enc = getDefaultEncodingName(); 294 if (enc != null) { 295 /* file.encoding has been set, so cache the converter class */ 296 fillCache = true; 297 } else { 298 /* file.encoding has not been set, so use a default encoding which 299 will not be cached */ 300 enc = "ISO8859_1"; 301 } 302 303 /* We have an encoding name; try to find its class */ 304 try { 305 c = getConverterClass(type, enc); 306 if (fillCache) { 307 cache(type, DEFAULT_NAME, c); 308 } 309 } catch (UnsupportedEncodingException x) { 310 /* Can't find the default class, so fall back to ISO 8859-1 */ 311 try { 312 c = getConverterClass(type, "ISO8859_1"); 313 } catch (UnsupportedEncodingException y) { 314 throw new InternalError("Cannot find default " 315 + converterPrefix[type] 316 + " converter class"); 317 } 318 } 319 return c; 320 321 } 322 323 /** 324 * Create a converter object that implements the given type of converter 325 * for the default encoding, falling back to ISO 8859-1 if the default 326 * encoding cannot be determined. 327 */ 328 static Object newDefaultConverter(int type) { 329 Class<?> c; 330 synchronized (lock) { 331 c = getDefaultConverterClass(type); 332 } 333 try { 334 return newConverter("", c); 335 } catch (UnsupportedEncodingException x) { 336 throw new InternalError("Cannot instantiate default converter" 337 + " class " + c.getName()); 338 } 339 } 340 341 }