jdk/src/share/classes/sun/io/Converters.java
changeset 10372 2f6d68f22eae
parent 10321 64f7ee2f31dd
parent 10371 7da2112e4236
child 10373 d4c5e59b82f8
equal deleted inserted replaced
10321:64f7ee2f31dd 10372:2f6d68f22eae
     1 /*
       
     2  * Copyright (c) 1998, 2010, 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 }