jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java
changeset 16705 1caaa379eded
parent 15993 cdc681a6afd7
child 18178 ee71c923891d
--- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Fri Mar 22 19:56:20 2013 +0400
+++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Wed Mar 27 16:19:51 2013 +0400
@@ -171,12 +171,12 @@
      * Lazy initialization of Standard Encodings.
      */
     private static class StandardEncodingsHolder {
-        private static final SortedSet standardEncodings = load();
-
-        private static SortedSet load() {
+        private static final SortedSet<String> standardEncodings = load();
+
+        private static SortedSet<String> load() {
             final Comparator comparator =
                     new CharsetComparator(IndexedComparator.SELECT_WORST);
-            final SortedSet tempSet = new TreeSet(comparator);
+            final SortedSet<String> tempSet = new TreeSet<String>(comparator);
             tempSet.add("US-ASCII");
             tempSet.add("ISO-8859-1");
             tempSet.add("UTF-8");
@@ -523,8 +523,8 @@
      * So as to avoid loading all available character converters, optional,
      * non-standard, character sets are not included.
      */
-    public static Iterator standardEncodings() {
-        return StandardEncodingsHolder.standardEncodings.iterator();
+    public static Set <String> standardEncodings() {
+        return StandardEncodingsHolder.standardEncodings;
     }
 
     /**
@@ -1068,17 +1068,10 @@
      *
      * Native to Java string conversion
      */
-    private String translateBytesOrStreamToString(InputStream str,  byte[] bytes,
-                                                    long format,
-                                                    Transferable localeTransferable)
+    private String translateBytesToString(byte[] bytes, long format,
+                                          Transferable localeTransferable)
             throws IOException
     {
-        // A String holds all of its data in memory at one time, so
-        // we can't avoid reading the entire InputStream at this point.
-        if (bytes == null) {
-            bytes = inputStreamToByteArray(str);
-        }
-        str.close();
 
         Long lFormat = Long.valueOf(format);
         String charset = getBestCharsetForTextFormat(lFormat, localeTransferable);
@@ -1221,13 +1214,13 @@
                     ("cannot transfer non-text data as Reader");
             }
 
-            Reader r = (Reader)obj;
             StringBuffer buf = new StringBuffer();
-            int c;
-            while ((c = r.read()) != -1) {
-                buf.append((char)c);
+            try (Reader r = (Reader)obj) {
+                int c;
+                while ((c = r.read()) != -1) {
+                    buf.append((char)c);
+                }
             }
-            r.close();
 
             return translateTransferableString(
                 buf.toString(),
@@ -1309,7 +1302,7 @@
             return bytes;
         }
 
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        byte[] theByteArray = null;
 
         // Target data is a file list. Source data must be a
         // java.util.List which contains java.io.File or String instances.
@@ -1324,8 +1317,9 @@
 
             final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
 
-            bos = convertFileListToBytes(fileList);
-
+            try (ByteArrayOutputStream bos = convertFileListToBytes(fileList)) {
+                theByteArray = bos.toByteArray();
+            }
 
         // Target data is a URI list. Source data must be a
         // java.util.List which contains java.io.File or String instances.
@@ -1360,57 +1354,72 @@
               }
 
             byte[] eoln = "\r\n".getBytes(targetCharset);
-            for (int i = 0; i < uriList.size(); i++) {
-                byte[] bytes = uriList.get(i).getBytes(targetCharset);
-                bos.write(bytes, 0, bytes.length);
-                bos.write(eoln, 0, eoln.length);
+
+            try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+                for (int i = 0; i < uriList.size(); i++) {
+                    byte[] bytes = uriList.get(i).getBytes(targetCharset);
+                    bos.write(bytes, 0, bytes.length);
+                    bos.write(eoln, 0, eoln.length);
+                }
+                theByteArray = bos.toByteArray();
             }
 
         // Source data is an InputStream. For arbitrary flavors, just grab the
         // bytes and dump them into a byte array. For text flavors, decode back
         // to a String and recur to reencode according to the requested format.
         } else if (flavor.isRepresentationClassInputStream()) {
-            InputStream is = (InputStream)obj;
-            boolean eof = false;
-            int avail = is.available();
-            byte[] tmp = new byte[avail > 8192 ? avail : 8192];
-            do {
-                int ret;
-                if (!(eof = (ret = is.read(tmp, 0, tmp.length)) == -1)) {
-                    bos.write(tmp, 0, ret);
+            try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+                try (InputStream is = (InputStream)obj) {
+                    boolean eof = false;
+                    int avail = is.available();
+                    byte[] tmp = new byte[avail > 8192 ? avail : 8192];
+                    do {
+                        int aValue;
+                        if (!(eof = (aValue = is.read(tmp, 0, tmp.length)) == -1)) {
+                            bos.write(tmp, 0, aValue);
+                        }
+                    } while (!eof);
                 }
-            } while (!eof);
-            is.close();
-
-            if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
-                byte[] bytes = bos.toByteArray();
-                bos.close();
-                String sourceEncoding = DataTransferer.getTextCharset(flavor);
-                return translateTransferableString(
-                    new String(bytes, sourceEncoding),
-                    format);
+
+                if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+                    byte[] bytes = bos.toByteArray();
+                    String sourceEncoding = DataTransferer.getTextCharset(flavor);
+                    return translateTransferableString(
+                               new String(bytes, sourceEncoding),
+                               format);
+                }
+                theByteArray = bos.toByteArray();
             }
 
+
+
         // Source data is an RMI object
         } else if (flavor.isRepresentationClassRemote()) {
+
             Object mo = RMI.newMarshalledObject(obj);
-            ObjectOutputStream oos = new ObjectOutputStream(bos);
-            oos.writeObject(mo);
-            oos.close();
-
-        // Source data is Serializable
+            theByteArray = convertObjectToBytes(mo);
+
+            // Source data is Serializable
         } else if (flavor.isRepresentationClassSerializable()) {
-            ObjectOutputStream oos = new ObjectOutputStream(bos);
-            oos.writeObject(obj);
-            oos.close();
+
+            theByteArray = convertObjectToBytes(obj);
 
         } else {
             throw new IOException("data translation failed");
         }
 
-        byte[] ret = bos.toByteArray();
-        bos.close();
-        return ret;
+
+
+        return theByteArray;
+    }
+
+    private static byte[] convertObjectToBytes(Object object) throws IOException {
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+             ObjectOutputStream oos = new ObjectOutputStream(bos))
+        {
+            oos.writeObject(object);
+            return bos.toByteArray();
+        }
     }
 
     protected abstract ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList) throws IOException;
@@ -1565,38 +1574,8 @@
                                  long format, Transferable localeTransferable)
         throws IOException
     {
-        return translateBytesOrStream(null, bytes, flavor, format,
-                                      localeTransferable);
-    }
-
-    public Object translateStream(InputStream str, DataFlavor flavor,
-                                  long format, Transferable localeTransferable)
-        throws IOException
-    {
-        return translateBytesOrStream(str, null, flavor, format,
-                                      localeTransferable);
-    }
-
-
-    /**
-     * Primary translation function for translating either a byte array or
-     * an InputStream into an Object, given a source format and a target
-     * DataFlavor.
-     *
-     * One of str/bytes is non-null; the other is null.
-     * The conversion from byte[] to InputStream is cheap, so do that
-     * immediately if necessary. The opposite conversion is expensive,
-     * so avoid it if possible.
-     */
-    protected Object translateBytesOrStream(InputStream str, byte[] bytes,
-                                            DataFlavor flavor, long format,
-                                            Transferable localeTransferable)
-        throws IOException
-    {
-
-        if (str == null) {
-            str = new ByteArrayInputStream(bytes);
-        }
+
+        Object theObject = null;
 
         // Source data is a file list. Use the dragQueryFile native function to
         // do most of the decoding. Then wrap File objects around the String
@@ -1605,12 +1584,8 @@
             if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
                 throw new IOException("data translation failed");
             }
-            if (bytes == null) {
-                bytes = inputStreamToByteArray(str);
-            }
             String[] filenames = dragQueryFile(bytes);
             if (filenames == null) {
-                str.close();
                 return null;
             }
 
@@ -1619,178 +1594,203 @@
             for (int i = 0; i < filenames.length; i++) {
                 files[i] = new File(filenames[i]);
             }
-            str.close();
 
             // Turn the list of Files into a List and return
-            return Arrays.asList(files);
-
-        // Source data is a URI list. Convert to DataFlavor.javaFileListFlavor
-        // where possible.
-        } else if (isURIListFormat(format) && DataFlavor.javaFileListFlavor.equals(flavor)) {
-            try {
-                URI uris[] = dragQueryURIs(str, bytes, format, localeTransferable);
-                if (uris == null) {
-                    return null;
-                }
-                ArrayList files = new ArrayList();
-                for (URI uri : uris) {
-                    try {
-                        files.add(new File(uri));
-                    } catch (IllegalArgumentException illegalArg) {
-                        // When converting from URIs to less generic files,
-                        // common practice (Wine, SWT) seems to be to
-                        // silently drop the URIs that aren't local files.
-                    }
-                }
-                return files;
-            } finally {
-                str.close();
-            }
-
-        // Target data is a String. Strip terminating NUL bytes. Decode bytes
-        // into characters. Search-and-replace EOLN.
+            theObject = Arrays.asList(files);
+
+            // Target data is a String. Strip terminating NUL bytes. Decode bytes
+            // into characters. Search-and-replace EOLN.
         } else if (String.class.equals(flavor.getRepresentationClass()) &&
-                   isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
-
-            return translateBytesOrStreamToString(
-                str, bytes,
-                format, localeTransferable);
-
-        // Special hack to maintain backwards-compatibility with the brokenness
-        // of StringSelection. Return a StringReader instead of an InputStream.
-        // Recur to obtain String and encapsulate.
-        } else if (DataFlavor.plainTextFlavor.equals(flavor)) {
-            return new StringReader(translateBytesOrStreamToString(
-                        str, bytes,
-                        format, localeTransferable));
-
-        // Target data is an InputStream. For arbitrary flavors, just return
-        // the raw bytes. For text flavors, decode to strip terminators and
-        // search-and-replace EOLN, then reencode according to the requested
-        // flavor.
-        } else if (flavor.isRepresentationClassInputStream()) {
-            return translateBytesOrStreamToInputStream(str, flavor, format,
-                                                       localeTransferable);
-
-        // Target data is a Reader. Obtain data in InputStream format, encoded
-        // as "Unicode" (utf-16be). Then use an InputStreamReader to decode
-        // back to chars on demand.
+                       isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+
+            theObject = translateBytesToString(bytes, format, localeTransferable);
+
+            // Target data is a Reader. Obtain data in InputStream format, encoded
+            // as "Unicode" (utf-16be). Then use an InputStreamReader to decode
+            // back to chars on demand.
         } else if (flavor.isRepresentationClassReader()) {
-            if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
-                throw new IOException
-                    ("cannot transfer non-text data as Reader");
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
+                theObject = translateStream(bais,
+                        flavor, format, localeTransferable);
             }
-
-            InputStream is = (InputStream)
-                translateBytesOrStreamToInputStream
-                    (str, DataFlavor.plainTextFlavor, format,
-                     localeTransferable);
-            String unicode =
-                DataTransferer.getTextCharset(DataFlavor.plainTextFlavor);
-            Reader reader = new InputStreamReader(is, unicode);
-
-            return constructFlavoredObject(reader, flavor, Reader.class);
-
-        // Target data is a CharBuffer. Recur to obtain String and wrap.
+            // Target data is a CharBuffer. Recur to obtain String and wrap.
         } else if (flavor.isRepresentationClassCharBuffer()) {
             if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
                 throw new IOException
-                    ("cannot transfer non-text data as CharBuffer");
+                          ("cannot transfer non-text data as CharBuffer");
             }
 
-            CharBuffer buffer = CharBuffer.wrap(translateBytesOrStreamToString(
-                str, bytes,
-                format, localeTransferable));
-
-            return constructFlavoredObject(buffer, flavor, CharBuffer.class);
-
-        // Target data is a char array. Recur to obtain String and convert to
-        // char array.
+            CharBuffer buffer = CharBuffer.wrap(
+                translateBytesToString(bytes,format, localeTransferable));
+
+            theObject = constructFlavoredObject(buffer, flavor, CharBuffer.class);
+
+            // Target data is a char array. Recur to obtain String and convert to
+            // char array.
         } else if (charArrayClass.equals(flavor.getRepresentationClass())) {
             if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
                 throw new IOException
-                    ("cannot transfer non-text data as char array");
+                          ("cannot transfer non-text data as char array");
             }
 
-            return translateBytesOrStreamToString(
-                    str, bytes,
-                    format, localeTransferable).toCharArray();
-
-        // Target data is a ByteBuffer. For arbitrary flavors, just return
-        // the raw bytes. For text flavors, convert to a String to strip
-        // terminators and search-and-replace EOLN, then reencode according to
-        // the requested flavor.
+            theObject = translateBytesToString(
+                bytes, format, localeTransferable).toCharArray();
+
+            // Target data is a ByteBuffer. For arbitrary flavors, just return
+            // the raw bytes. For text flavors, convert to a String to strip
+            // terminators and search-and-replace EOLN, then reencode according to
+            // the requested flavor.
         } else if (flavor.isRepresentationClassByteBuffer()) {
             if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
-                bytes = translateBytesOrStreamToString(
-                    str, bytes,
-                    format, localeTransferable
-                ).getBytes(
-                    DataTransferer.getTextCharset(flavor)
-                );
-            } else {
-                if (bytes == null) {
-                    bytes = inputStreamToByteArray(str);
-                }
+                bytes = translateBytesToString(
+                    bytes, format, localeTransferable).getBytes(
+                        DataTransferer.getTextCharset(flavor)
+                    );
             }
 
             ByteBuffer buffer = ByteBuffer.wrap(bytes);
-            return constructFlavoredObject(buffer, flavor, ByteBuffer.class);
-
-        // Target data is a byte array. For arbitrary flavors, just return
-        // the raw bytes. For text flavors, convert to a String to strip
-        // terminators and search-and-replace EOLN, then reencode according to
-        // the requested flavor.
+            theObject = constructFlavoredObject(buffer, flavor, ByteBuffer.class);
+
+            // Target data is a byte array. For arbitrary flavors, just return
+            // the raw bytes. For text flavors, convert to a String to strip
+            // terminators and search-and-replace EOLN, then reencode according to
+            // the requested flavor.
         } else if (byteArrayClass.equals(flavor.getRepresentationClass())) {
             if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
-                return translateBytesOrStreamToString(
-                    str, bytes,
-                    format, localeTransferable
-                ).getBytes(
-                    DataTransferer.getTextCharset(flavor)
-                );
+                theObject = translateBytesToString(
+                    bytes, format, localeTransferable
+                ).getBytes(DataTransferer.getTextCharset(flavor));
             } else {
-                return (bytes != null) ? bytes : inputStreamToByteArray(str);
+                theObject = bytes;
             }
 
-        // Target data is an RMI object
-        } else if (flavor.isRepresentationClassRemote()) {
-            try {
-                byte[] ba = inputStreamToByteArray(str);
-                ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(ba));
-                Object ret = RMI.getMarshalledObject(ois.readObject());
-                ois.close();
-                str.close();
-                return ret;
-            } catch (Exception e) {
-                throw new IOException(e.getMessage());
+            // Target data is an InputStream. For arbitrary flavors, just return
+            // the raw bytes. For text flavors, decode to strip terminators and
+            // search-and-replace EOLN, then reencode according to the requested
+            // flavor.
+        } else if (flavor.isRepresentationClassInputStream()) {
+
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
+                theObject = translateStream(bais, flavor, format, localeTransferable);
             }
 
-        // Target data is Serializable
+            // Target data is Serializable
         } else if (flavor.isRepresentationClassSerializable()) {
-            try {
-                byte[] ba = inputStreamToByteArray(str);
-                ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(ba));
-                Object ret = ois.readObject();
-                ois.close();
-                str.close();
-                return ret;
-            } catch (Exception e) {
-                throw new IOException(e.getMessage());
+
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
+                theObject = translateStream(bais, flavor, format, localeTransferable);
             }
 
-        // Target data is Image
+            // Target data is Image
         } else if (DataFlavor.imageFlavor.equals(flavor)) {
             if (!isImageFormat(format)) {
                 throw new IOException("data translation failed");
             }
 
-            Image image = platformImageBytesOrStreamToImage(str, bytes, format);
-            str.close();
-            return image;
+            theObject = platformImageBytesToImage(bytes, format);
+        }
+
+        if (theObject == null) {
+            throw new IOException("data translation failed");
         }
 
-        throw new IOException("data translation failed");
+        return theObject;
+
+    }
+
+    /**
+     * Primary translation function for translating
+     * an InputStream into an Object, given a source format and a target
+     * DataFlavor.
+     */
+    public Object translateStream(InputStream str, DataFlavor flavor,
+                                  long format, Transferable localeTransferable)
+        throws IOException
+    {
+
+        Object theObject = null;
+        // Source data is a URI list. Convert to DataFlavor.javaFileListFlavor
+        // where possible.
+        if (isURIListFormat(format)
+                && DataFlavor.javaFileListFlavor.equals(flavor))
+        {
+
+            URI uris[] = dragQueryURIs(str, format, localeTransferable);
+            if (uris == null) {
+                return null;
+            }
+            ArrayList files = new ArrayList();
+            for (URI uri : uris) {
+                try {
+                    files.add(new File(uri));
+                } catch (IllegalArgumentException illegalArg) {
+                    // When converting from URIs to less generic files,
+                    // common practice (Wine, SWT) seems to be to
+                    // silently drop the URIs that aren't local files.
+                }
+            }
+            theObject = files;
+
+            // Special hack to maintain backwards-compatibility with the brokenness
+            // of StringSelection. Return a StringReader instead of an InputStream.
+            // Recur to obtain String and encapsulate.
+        } else if (DataFlavor.plainTextFlavor.equals(flavor)) {
+            theObject = new StringReader(translateBytesToString(
+                inputStreamToByteArray(str),
+                format, localeTransferable));
+
+            // Target data is an InputStream. For arbitrary flavors, just return
+            // the raw bytes. For text flavors, decode to strip terminators and
+            // search-and-replace EOLN, then reencode according to the requested
+            // flavor.
+        } else if (flavor.isRepresentationClassInputStream()) {
+            theObject = translateStreamToInputStream(str, flavor, format,
+                                                               localeTransferable);
+
+            // Target data is a Reader. Obtain data in InputStream format, encoded
+            // as "Unicode" (utf-16be). Then use an InputStreamReader to decode
+            // back to chars on demand.
+        } else if (flavor.isRepresentationClassReader()) {
+            if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
+                throw new IOException
+                          ("cannot transfer non-text data as Reader");
+            }
+
+            InputStream is = (InputStream)translateStreamToInputStream(
+                    str, DataFlavor.plainTextFlavor,
+                    format, localeTransferable);
+
+            String unicode = DataTransferer.getTextCharset(DataFlavor.plainTextFlavor);
+
+            Reader reader = new InputStreamReader(is, unicode);
+
+            theObject = constructFlavoredObject(reader, flavor, Reader.class);
+
+            // Target data is an RMI object
+        } else if (flavor.isRepresentationClassRemote()) {
+
+            try (ObjectInputStream ois =
+                     new ObjectInputStream(str))
+            {
+                theObject = RMI.getMarshalledObject(ois.readObject());
+            }catch (Exception e) {
+                throw new IOException(e.getMessage());
+            }
+
+            // Target data is Serializable
+        } else if (flavor.isRepresentationClassSerializable()) {
+            try (ObjectInputStream ois =
+                     new ObjectInputStream(str))
+            {
+                theObject = ois.readObject();
+            } catch (Exception e) {
+                throw new IOException(e.getMessage());
+            }
+        }
+
+
+        return theObject;
+
     }
 
     /**
@@ -1798,7 +1798,7 @@
      * ReencodingInputStream will decode and reencode the InputStream on demand
      * so that we can strip terminators and search-and-replace EOLN.
      */
-    private Object translateBytesOrStreamToInputStream
+    private Object translateStreamToInputStream
         (InputStream str, DataFlavor flavor, long format,
          Transferable localeTransferable) throws IOException
     {
@@ -2054,7 +2054,6 @@
      * Decodes URIs from either a byte array or a stream.
      */
     protected URI[] dragQueryURIs(InputStream stream,
-                                  byte[] bytes,
                                   long format,
                                   Transferable localeTransferable)
       throws IOException
@@ -2067,10 +2066,10 @@
      * Translates either a byte array or an input stream which contain
      * platform-specific image data in the given format into an Image.
      */
-    protected abstract Image platformImageBytesOrStreamToImage(InputStream str,
-                                                               byte[] bytes,
-                                                               long format)
-      throws IOException;
+
+
+    protected abstract Image platformImageBytesToImage(
+        byte[] bytes,long format) throws IOException;
 
     /**
      * Translates either a byte array or an input stream which contain
@@ -2078,13 +2077,9 @@
      *
      * @param mimeType image MIME type, such as: image/png, image/jpeg, image/gif
      */
-    protected Image standardImageBytesOrStreamToImage(InputStream inputStream,
-                                                      byte[] bytes,
-                                                      String mimeType)
-      throws IOException {
-        if (inputStream == null) {
-            inputStream = new ByteArrayInputStream(bytes);
-        }
+    protected Image standardImageBytesToImage(
+        byte[] bytes, String mimeType) throws IOException
+    {
 
         Iterator readerIterator = ImageIO.getImageReadersByMIMEType(mimeType);
 
@@ -2097,9 +2092,9 @@
 
         while (readerIterator.hasNext()) {
             ImageReader imageReader = (ImageReader)readerIterator.next();
-            try {
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
                 ImageInputStream imageInputStream =
-                    ImageIO.createImageInputStream(inputStream);
+                    ImageIO.createImageInputStream(bais);
 
                 try {
                     ImageReadParam param = imageReader.getDefaultReadParam();
@@ -2456,15 +2451,16 @@
     protected static byte[] inputStreamToByteArray(InputStream str)
         throws IOException
     {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        int len = 0;
-        byte[] buf = new byte[8192];
-
-        while ((len = str.read(buf)) != -1) {
-            baos.write(buf, 0, len);
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            int len = 0;
+            byte[] buf = new byte[8192];
+
+            while ((len = str.read(buf)) != -1) {
+                baos.write(buf, 0, len);
+            }
+
+            return baos.toByteArray();
         }
-
-        return baos.toByteArray();
     }
 
     /**