Converters.java 12.0 KB
Newer Older
D
duke 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
/*
 * Copyright 1998-2006 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package sun.io;

import java.io.UnsupportedEncodingException;
import java.lang.ref.SoftReference;
import java.util.Properties;

/**
 * Package-private utility class that caches the default converter classes and
 * provides other logic common to both the ByteToCharConverter and
 * CharToByteConverter classes.
 *
 * @author   Mark Reinhold
 * @since    1.2
 *
 * @deprecated Replaced by {@link java.nio.charset}.  THIS API WILL BE
 * REMOVED IN J2SE 1.6.
 */
@Deprecated
public class Converters {

    private Converters() { }    /* To prevent instantiation */

    /* Lock for all static fields in this class */
    private static Object lock = Converters.class;

    /* Cached values of system properties */
    private static String converterPackageName = null;  /* file.encoding.pkg */
    private static String defaultEncoding = null;       /* file.encoding */

    /* Converter type constants and names */
    public static final int BYTE_TO_CHAR = 0;
    public static final int CHAR_TO_BYTE = 1;
    private static final String[] converterPrefix = { "ByteToChar",
                                                      "CharToByte" };


    // -- Converter class cache --

    private static final int CACHE_SIZE = 3;

    /* For the default charset, whatever it turns out to be */
    private static final Object DEFAULT_NAME = new Object();

    /* Cached converter classes, CACHE_SIZE per converter type.  Each cache
     * entry is a soft reference to a two-object array; the first element of
     * the array is the converter class, the second is an object (typically a
     * string) representing the encoding name that was used to request the
     * converter, e.g.,
     *
     *     ((Object[])classCache[CHAR_TO_BYTE][i].get())[0]
     *
     * will be a CharToByteConverter and
     *
     *     ((Object[])classCache[CHAR_TO_BYTE][i].get())[1]
     *
     * will be the string encoding name used to request it, assuming that cache
     * entry i is valid.
     *
     * Ordinarily we'd do this with a private static utility class, but since
     * this code can be involved in the startup sequence it's important to keep
     * the footprint down.
     */
88 89 90 91 92
    @SuppressWarnings("unchecked")
    private static SoftReference<Object[]>[][] classCache
        = (SoftReference<Object[]>[][]) new SoftReference<?>[][] {
            new SoftReference<?>[CACHE_SIZE],
            new SoftReference<?>[CACHE_SIZE]
D
duke 已提交
93 94 95 96 97 98 99 100 101
        };

    private static void moveToFront(Object[] oa, int i) {
        Object ob = oa[i];
        for (int j = i; j > 0; j--)
            oa[j] = oa[j - 1];
        oa[0] = ob;
    }

102 103
    private static Class<?> cache(int type, Object encoding) {
        SoftReference<Object[]>[] srs = classCache[type];
D
duke 已提交
104
        for (int i = 0; i < CACHE_SIZE; i++) {
105
            SoftReference<Object[]> sr = srs[i];
D
duke 已提交
106 107
            if (sr == null)
                continue;
108
            Object[] oa = sr.get();
D
duke 已提交
109 110 111 112 113 114
            if (oa == null) {
                srs[i] = null;
                continue;
            }
            if (oa[1].equals(encoding)) {
                moveToFront(srs, i);
115
                return (Class<?>)oa[0];
D
duke 已提交
116 117 118 119 120
            }
        }
        return null;
    }

121 122 123
    private static Class<?> cache(int type, Object encoding, Class<?> c) {
        SoftReference<Object[]>[] srs = classCache[type];
        srs[CACHE_SIZE - 1] = new SoftReference<Object[]>(new Object[] { c, encoding });
D
duke 已提交
124 125 126 127 128 129 130 131 132
        moveToFront(srs, CACHE_SIZE - 1);
        return c;
    }

    /* Used to avoid doing expensive charset lookups for charsets that are not
     * yet directly supported by NIO.
     */
    public static boolean isCached(int type, String encoding) {
        synchronized (lock) {
133
            SoftReference<Object[]>[] srs = classCache[type];
D
duke 已提交
134
            for (int i = 0; i < CACHE_SIZE; i++) {
135
                SoftReference<Object[]> sr = srs[i];
D
duke 已提交
136 137
                if (sr == null)
                    continue;
138
                Object[] oa = sr.get();
D
duke 已提交
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
                if (oa == null) {
                    srs[i] = null;
                    continue;
                }
                if (oa[1].equals(encoding))
                    return true;
            }
            return false;
        }
    }



    /** Get the name of the converter package */
    private static String getConverterPackageName() {
        String cp = converterPackageName;
        if (cp != null) return cp;
156
        java.security.PrivilegedAction<String> pa =
D
duke 已提交
157
            new sun.security.action.GetPropertyAction("file.encoding.pkg");
158
        cp = java.security.AccessController.doPrivileged(pa);
D
duke 已提交
159 160 161 162 163 164 165 166 167 168 169 170 171
        if (cp != null) {
            /* Property is set, so take it as the true converter package */
            converterPackageName = cp;
        } else {
            /* Fall back to sun.io */
            cp = "sun.io";
        }
        return cp;
    }

    public static String getDefaultEncodingName() {
        synchronized (lock) {
            if (defaultEncoding == null) {
172
                java.security.PrivilegedAction<String> pa =
D
duke 已提交
173
                    new sun.security.action.GetPropertyAction("file.encoding");
174
                defaultEncoding = java.security.AccessController.doPrivileged(pa);
D
duke 已提交
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
            }
        }
        return defaultEncoding;
    }

    public static void resetDefaultEncodingName() {
        // This method should only be called during VM initialization.
        if (sun.misc.VM.isBooted())
            return;

        synchronized (lock) {
            defaultEncoding = "ISO-8859-1";
            Properties p = System.getProperties();
            p.setProperty("file.encoding", defaultEncoding);
            System.setProperties(p);
        }
    }

    /**
     * Get the class that implements the given type of converter for the named
     * encoding, or throw an UnsupportedEncodingException if no such class can
     * be found
     */
198
    private static Class<?> getConverterClass(int type, String encoding)
D
duke 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
        throws UnsupportedEncodingException
    {
        String enc = null;

        /* "ISO8859_1" is the canonical name for the ISO-Latin-1 encoding.
           Native code in the JDK commonly uses the alias "8859_1" instead of
           "ISO8859_1".  We hardwire this alias here in order to avoid loading
           the full alias table just for this case. */
        if (!encoding.equals("ISO8859_1")) {
            if (encoding.equals("8859_1")) {
                enc = "ISO8859_1";
            /*
             * On Solaris with nl_langinfo() called in GetJavaProperties():
             *
             *   locale undefined -> NULL -> hardcoded default
             *   "C" locale       -> "" -> hardcoded default    (on 2.6)
             *   "C" locale       -> "646"                      (on 2.7)
             *   "en_US" locale -> "ISO8859-1"
             *   "en_GB" locale -> "ISO8859-1"                  (on 2.7)
             *   "en_UK" locale -> "ISO8859-1"                  (on 2.6)
             */
            } else if (encoding.equals("ISO8859-1")) {
                enc = "ISO8859_1";
            } else if (encoding.equals("646")) {
                enc = "ASCII";
            } else {
                enc = CharacterEncoding.aliasName(encoding);
            }
        }
        if (enc == null) {
            enc = encoding;
        }

        try {
            return Class.forName(getConverterPackageName()
                                 + "." + converterPrefix[type] + enc);
        } catch(ClassNotFoundException e) {
            throw new UnsupportedEncodingException(enc);
        }

    }

    /**
     * Instantiate the given converter class, or throw an
     * UnsupportedEncodingException if it cannot be instantiated
     */
245
    private static Object newConverter(String enc, Class<?> c)
D
duke 已提交
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
        throws UnsupportedEncodingException
    {
        try {
            return c.newInstance();
        } catch(InstantiationException e) {
            throw new UnsupportedEncodingException(enc);
        } catch(IllegalAccessException e) {
            throw new UnsupportedEncodingException(enc);
        }
    }

    /**
     * Create a converter object that implements the given type of converter
     * for the given encoding, or throw an UnsupportedEncodingException if no
     * appropriate converter class can be found and instantiated
     */
    static Object newConverter(int type, String enc)
        throws UnsupportedEncodingException
    {
265
        Class<?> c;
D
duke 已提交
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
        synchronized (lock) {
            c = cache(type, enc);
            if (c == null) {
                c = getConverterClass(type, enc);
                if (!c.getName().equals("sun.io.CharToByteUTF8"))
                    cache(type, enc, c);
            }
        }
        return newConverter(enc, c);
    }

    /**
     * Find the class that implements the given type of converter for the
     * default encoding.  If the default encoding cannot be determined or is
     * not yet defined, return a class that implements the fallback default
     * encoding, which is just ISO 8859-1.
     */
283
    private static Class<?> getDefaultConverterClass(int type) {
D
duke 已提交
284
        boolean fillCache = false;
285
        Class<?> c;
D
duke 已提交
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328

        /* First check the class cache */
        c = cache(type, DEFAULT_NAME);
        if (c != null)
            return c;

        /* Determine the encoding name */
        String enc = getDefaultEncodingName();
        if (enc != null) {
            /* file.encoding has been set, so cache the converter class */
            fillCache = true;
        } else {
            /* file.encoding has not been set, so use a default encoding which
               will not be cached */
            enc = "ISO8859_1";
        }

        /* We have an encoding name; try to find its class */
        try {
            c = getConverterClass(type, enc);
            if (fillCache) {
                cache(type, DEFAULT_NAME, c);
            }
        } catch (UnsupportedEncodingException x) {
            /* Can't find the default class, so fall back to ISO 8859-1 */
            try {
                c = getConverterClass(type, "ISO8859_1");
            } catch (UnsupportedEncodingException y) {
                throw new InternalError("Cannot find default "
                                        + converterPrefix[type]
                                        + " converter class");
            }
        }
        return c;

    }

    /**
     * Create a converter object that implements the given type of converter
     * for the default encoding, falling back to ISO 8859-1 if the default
     * encoding cannot be determined.
     */
    static Object newDefaultConverter(int type) {
329
        Class<?> c;
D
duke 已提交
330 331 332 333 334 335 336 337 338 339 340 341
        synchronized (lock) {
            c = getDefaultConverterClass(type);
        }
        try {
            return newConverter("", c);
        } catch (UnsupportedEncodingException x) {
            throw new InternalError("Cannot instantiate default converter"
                                    + " class " + c.getName());
        }
    }

}