blob: 9b6959b5d61cab930d2e36e4dddda030330a4eed [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.io;
27
28import java.io.UnsupportedEncodingException;
29import java.lang.ref.SoftReference;
30import 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
44public 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 private static SoftReference[][] classCache
89 = new SoftReference[][] {
90 new SoftReference[CACHE_SIZE],
91 new SoftReference[CACHE_SIZE]
92 };
93
94 private static void moveToFront(Object[] oa, int i) {
95 Object ob = oa[i];
96 for (int j = i; j > 0; j--)
97 oa[j] = oa[j - 1];
98 oa[0] = ob;
99 }
100
101 private static Class cache(int type, Object encoding) {
102 SoftReference[] srs = classCache[type];
103 for (int i = 0; i < CACHE_SIZE; i++) {
104 SoftReference sr = srs[i];
105 if (sr == null)
106 continue;
107 Object[] oa = (Object[])sr.get();
108 if (oa == null) {
109 srs[i] = null;
110 continue;
111 }
112 if (oa[1].equals(encoding)) {
113 moveToFront(srs, i);
114 return (Class)oa[0];
115 }
116 }
117 return null;
118 }
119
120 private static Class cache(int type, Object encoding, Class c) {
121 SoftReference[] srs = classCache[type];
122 srs[CACHE_SIZE - 1] = new SoftReference(new Object[] { c, encoding });
123 moveToFront(srs, CACHE_SIZE - 1);
124 return c;
125 }
126
127 /* Used to avoid doing expensive charset lookups for charsets that are not
128 * yet directly supported by NIO.
129 */
130 public static boolean isCached(int type, String encoding) {
131 synchronized (lock) {
132 SoftReference[] srs = classCache[type];
133 for (int i = 0; i < CACHE_SIZE; i++) {
134 SoftReference sr = srs[i];
135 if (sr == null)
136 continue;
137 Object[] oa = (Object[])sr.get();
138 if (oa == null) {
139 srs[i] = null;
140 continue;
141 }
142 if (oa[1].equals(encoding))
143 return true;
144 }
145 return false;
146 }
147 }
148
149
150
151 /** Get the name of the converter package */
152 private static String getConverterPackageName() {
153 String cp = converterPackageName;
154 if (cp != null) return cp;
155 java.security.PrivilegedAction pa =
156 new sun.security.action.GetPropertyAction("file.encoding.pkg");
157 cp = (String)java.security.AccessController.doPrivileged(pa);
158 if (cp != null) {
159 /* Property is set, so take it as the true converter package */
160 converterPackageName = cp;
161 } else {
162 /* Fall back to sun.io */
163 cp = "sun.io";
164 }
165 return cp;
166 }
167
168 public static String getDefaultEncodingName() {
169 synchronized (lock) {
170 if (defaultEncoding == null) {
171 java.security.PrivilegedAction pa =
172 new sun.security.action.GetPropertyAction("file.encoding");
173 defaultEncoding = (String)java.security.AccessController.doPrivileged(pa);
174 }
175 }
176 return defaultEncoding;
177 }
178
179 public static void resetDefaultEncodingName() {
180 // This method should only be called during VM initialization.
181 if (sun.misc.VM.isBooted())
182 return;
183
184 synchronized (lock) {
185 defaultEncoding = "ISO-8859-1";
186 Properties p = System.getProperties();
187 p.setProperty("file.encoding", defaultEncoding);
188 System.setProperties(p);
189 }
190 }
191
192 /**
193 * Get the class that implements the given type of converter for the named
194 * encoding, or throw an UnsupportedEncodingException if no such class can
195 * be found
196 */
197 private static Class getConverterClass(int type, String encoding)
198 throws UnsupportedEncodingException
199 {
200 String enc = null;
201
202 /* "ISO8859_1" is the canonical name for the ISO-Latin-1 encoding.
203 Native code in the JDK commonly uses the alias "8859_1" instead of
204 "ISO8859_1". We hardwire this alias here in order to avoid loading
205 the full alias table just for this case. */
206 if (!encoding.equals("ISO8859_1")) {
207 if (encoding.equals("8859_1")) {
208 enc = "ISO8859_1";
209 /*
210 * On Solaris with nl_langinfo() called in GetJavaProperties():
211 *
212 * locale undefined -> NULL -> hardcoded default
213 * "C" locale -> "" -> hardcoded default (on 2.6)
214 * "C" locale -> "646" (on 2.7)
215 * "en_US" locale -> "ISO8859-1"
216 * "en_GB" locale -> "ISO8859-1" (on 2.7)
217 * "en_UK" locale -> "ISO8859-1" (on 2.6)
218 */
219 } else if (encoding.equals("ISO8859-1")) {
220 enc = "ISO8859_1";
221 } else if (encoding.equals("646")) {
222 enc = "ASCII";
223 } else {
224 enc = CharacterEncoding.aliasName(encoding);
225 }
226 }
227 if (enc == null) {
228 enc = encoding;
229 }
230
231 try {
232 return Class.forName(getConverterPackageName()
233 + "." + converterPrefix[type] + enc);
234 } catch(ClassNotFoundException e) {
235 throw new UnsupportedEncodingException(enc);
236 }
237
238 }
239
240 /**
241 * Instantiate the given converter class, or throw an
242 * UnsupportedEncodingException if it cannot be instantiated
243 */
244 private static Object newConverter(String enc, Class c)
245 throws UnsupportedEncodingException
246 {
247 try {
248 return c.newInstance();
249 } catch(InstantiationException e) {
250 throw new UnsupportedEncodingException(enc);
251 } catch(IllegalAccessException e) {
252 throw new UnsupportedEncodingException(enc);
253 }
254 }
255
256 /**
257 * Create a converter object that implements the given type of converter
258 * for the given encoding, or throw an UnsupportedEncodingException if no
259 * appropriate converter class can be found and instantiated
260 */
261 static Object newConverter(int type, String enc)
262 throws UnsupportedEncodingException
263 {
264 Class c;
265 synchronized (lock) {
266 c = cache(type, enc);
267 if (c == null) {
268 c = getConverterClass(type, enc);
269 if (!c.getName().equals("sun.io.CharToByteUTF8"))
270 cache(type, enc, c);
271 }
272 }
273 return newConverter(enc, c);
274 }
275
276 /**
277 * Find the class that implements the given type of converter for the
278 * default encoding. If the default encoding cannot be determined or is
279 * not yet defined, return a class that implements the fallback default
280 * encoding, which is just ISO 8859-1.
281 */
282 private static Class getDefaultConverterClass(int type) {
283 boolean fillCache = false;
284 Class c;
285
286 /* First check the class cache */
287 c = cache(type, DEFAULT_NAME);
288 if (c != null)
289 return c;
290
291 /* Determine the encoding name */
292 String enc = getDefaultEncodingName();
293 if (enc != null) {
294 /* file.encoding has been set, so cache the converter class */
295 fillCache = true;
296 } else {
297 /* file.encoding has not been set, so use a default encoding which
298 will not be cached */
299 enc = "ISO8859_1";
300 }
301
302 /* We have an encoding name; try to find its class */
303 try {
304 c = getConverterClass(type, enc);
305 if (fillCache) {
306 cache(type, DEFAULT_NAME, c);
307 }
308 } catch (UnsupportedEncodingException x) {
309 /* Can't find the default class, so fall back to ISO 8859-1 */
310 try {
311 c = getConverterClass(type, "ISO8859_1");
312 } catch (UnsupportedEncodingException y) {
313 throw new InternalError("Cannot find default "
314 + converterPrefix[type]
315 + " converter class");
316 }
317 }
318 return c;
319
320 }
321
322 /**
323 * Create a converter object that implements the given type of converter
324 * for the default encoding, falling back to ISO 8859-1 if the default
325 * encoding cannot be determined.
326 */
327 static Object newDefaultConverter(int type) {
328 Class c;
329 synchronized (lock) {
330 c = getDefaultConverterClass(type);
331 }
332 try {
333 return newConverter("", c);
334 } catch (UnsupportedEncodingException x) {
335 throw new InternalError("Cannot instantiate default converter"
336 + " class " + c.getName());
337 }
338 }
339
340}