8037485: Refactor java.awt.datatransfer to eliminate dependency on AWT
authorpchelko
Mon, 28 Jul 2014 19:02:56 +0400
changeset 26010 9a3cf8ee0776
parent 26009 682a3a6d43a7
child 26011 0fa4f1bd2843
8037485: Refactor java.awt.datatransfer to eliminate dependency on AWT Reviewed-by: alanb, mchung, plevart, serb
jdk/src/share/classes/java/awt/datatransfer/Clipboard.java
jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java
jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java
jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java
jdk/src/share/classes/sun/awt/datatransfer/DesktopDatatransferServiceImpl.java
jdk/src/share/classes/sun/awt/datatransfer/META-INF/services/sun.datatransfer.DesktopDatatransferService
jdk/src/share/classes/sun/datatransfer/DataFlavorUtil.java
jdk/src/share/classes/sun/datatransfer/DesktopDatatransferService.java
jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java
jdk/test/java/awt/datatransfer/SystemFlavorMap/AddFlavorTest.java
--- a/jdk/src/share/classes/java/awt/datatransfer/Clipboard.java	Mon Jul 28 18:43:09 2014 +0400
+++ b/jdk/src/share/classes/java/awt/datatransfer/Clipboard.java	Mon Jul 28 19:02:56 2014 +0400
@@ -25,7 +25,7 @@
 
 package java.awt.datatransfer;
 
-import java.awt.EventQueue;
+import sun.datatransfer.DataFlavorUtil;
 
 import java.util.Objects;
 import java.util.Set;
@@ -130,7 +130,8 @@
         this.contents = contents;
 
         if (oldOwner != null && oldOwner != owner) {
-            EventQueue.invokeLater(() -> oldOwner.lostOwnership(Clipboard.this, oldContents));
+            DataFlavorUtil.getDesktopService().invokeOnEventThread(() ->
+                    oldOwner.lostOwnership(Clipboard.this, oldContents));
         }
         fireFlavorsChanged();
     }
@@ -324,7 +325,7 @@
             return;
         }
         flavorListeners.forEach(listener ->
-                EventQueue.invokeLater(() ->
+                DataFlavorUtil.getDesktopService().invokeOnEventThread(() ->
                         listener.flavorsChanged(new FlavorEvent(Clipboard.this))));
     }
 
--- a/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java	Mon Jul 28 18:43:09 2014 +0400
+++ b/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java	Mon Jul 28 19:02:56 2014 +0400
@@ -25,7 +25,7 @@
 
 package java.awt.datatransfer;
 
-import sun.awt.datatransfer.DataTransferer;
+import sun.datatransfer.DataFlavorUtil;
 import sun.reflect.misc.ReflectUtil;
 
 import java.io.ByteArrayInputStream;
@@ -44,7 +44,6 @@
 import java.nio.CharBuffer;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.Objects;
 
 import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
@@ -582,12 +581,12 @@
         } else {
            params += representationClass.getName();
         }
-        if (DataTransferer.isFlavorCharsetTextType(this) &&
+        if (DataFlavorUtil.isFlavorCharsetTextType(this) &&
             (isRepresentationClassInputStream() ||
              isRepresentationClassByteBuffer() ||
              byte[].class.equals(representationClass)))
         {
-            params += ";charset=" + DataTransferer.getTextCharset(this);
+            params += ";charset=" + DataFlavorUtil.getTextCharset(this);
         }
         return params;
     }
@@ -609,13 +608,8 @@
      * @since 1.3
      */
     public static final DataFlavor getTextPlainUnicodeFlavor() {
-        String encoding = null;
-        DataTransferer transferer = DataTransferer.getInstance();
-        if (transferer != null) {
-            encoding = transferer.getDefaultUnicodeEncoding();
-        }
         return new DataFlavor(
-            "text/plain;charset="+encoding
+            "text/plain;charset=" + DataFlavorUtil.getDesktopService().getDefaultUnicodeEncoding()
             +";class=java.io.InputStream", "Plain Text");
     }
 
@@ -741,12 +735,8 @@
             return null;
         }
 
-        if (textFlavorComparator == null) {
-            textFlavorComparator = new TextFlavorComparator();
-        }
-
         DataFlavor bestFlavor = Collections.max(Arrays.asList(availableFlavors),
-                                                textFlavorComparator);
+                                                DataFlavorUtil.getTextFlavorComparator());
 
         if (!bestFlavor.isFlavorTextType()) {
             return null;
@@ -755,46 +745,6 @@
         return bestFlavor;
     }
 
-    private static Comparator<DataFlavor> textFlavorComparator;
-
-    static class TextFlavorComparator
-            extends DataTransferer.DataFlavorComparator {
-
-        /**
-         * Compares two <code>DataFlavor</code> objects. Returns a negative
-         * integer, zero, or a positive integer as the first
-         * <code>DataFlavor</code> is worse than, equal to, or better than the
-         * second.
-         * <p>
-         * <code>DataFlavor</code>s are ordered according to the rules outlined
-         * for <code>selectBestTextFlavor</code>.
-         *
-         * @param flavor1 the first <code>DataFlavor</code> to be compared
-         * @param flavor2 the second <code>DataFlavor</code> to be compared
-         * @return a negative integer, zero, or a positive integer as the first
-         *         argument is worse, equal to, or better than the second
-         * @throws ClassCastException if either of the arguments is not an
-         *         instance of <code>DataFlavor</code>
-         * @throws NullPointerException if either of the arguments is
-         *         <code>null</code>
-         *
-         * @see #selectBestTextFlavor
-         */
-        public int compare(DataFlavor flavor1, DataFlavor flavor2) {
-            if (flavor1.isFlavorTextType()) {
-                if (flavor2.isFlavorTextType()) {
-                    return super.compare(flavor1, flavor2);
-                } else {
-                    return 1;
-                }
-            } else if (flavor2.isFlavorTextType()) {
-                return -1;
-            } else {
-                return 0;
-            }
-        }
-    }
-
     /**
      * Gets a Reader for a text flavor, decoded, if necessary, for the expected
      * charset (encoding). The supported representation classes are
@@ -1015,13 +965,13 @@
             }
 
             if ("text".equals(getPrimaryType())) {
-                if (DataTransferer.doesSubtypeSupportCharset(this)
+                if (DataFlavorUtil.doesSubtypeSupportCharset(this)
                         && representationClass != null
                         && !isStandardTextRepresentationClass()) {
                     String thisCharset =
-                            DataTransferer.canonicalName(this.getParameter("charset"));
+                            DataFlavorUtil.canonicalName(this.getParameter("charset"));
                     String thatCharset =
-                            DataTransferer.canonicalName(that.getParameter("charset"));
+                            DataFlavorUtil.canonicalName(that.getParameter("charset"));
                     if (!Objects.equals(thisCharset, thatCharset)) {
                         return false;
                     }
@@ -1088,10 +1038,10 @@
             // subTypes is '*', regardless of the other subType.
 
             if ("text".equals(primaryType)) {
-                if (DataTransferer.doesSubtypeSupportCharset(this)
+                if (DataFlavorUtil.doesSubtypeSupportCharset(this)
                         && representationClass != null
                         && !isStandardTextRepresentationClass()) {
-                    String charset = DataTransferer.canonicalName(getParameter("charset"));
+                    String charset = DataFlavorUtil.canonicalName(getParameter("charset"));
                     if (charset != null) {
                         total += charset.hashCode();
                     }
@@ -1280,9 +1230,8 @@
     * Returns true if the representation class is <code>Remote</code>.
     * @return true if the representation class is <code>Remote</code>
     */
-
     public boolean isRepresentationClassRemote() {
-        return DataTransferer.isRemote(representationClass);
+        return DataFlavorUtil.RMI.isRemote(representationClass);
     }
 
    /**
@@ -1356,8 +1305,8 @@
      * @since 1.4
      */
     public boolean isFlavorTextType() {
-        return (DataTransferer.isFlavorCharsetTextType(this) ||
-                DataTransferer.isFlavorNoncharsetTextType(this));
+        return (DataFlavorUtil.isFlavorCharsetTextType(this) ||
+                DataFlavorUtil.isFlavorNoncharsetTextType(this));
     }
 
    /**
--- a/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java	Mon Jul 28 18:43:09 2014 +0400
+++ b/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java	Mon Jul 28 19:02:56 2014 +0400
@@ -25,22 +25,15 @@
 
 package java.awt.datatransfer;
 
-import java.awt.Toolkit;
-
-import java.io.BufferedInputStream;
-import java.io.InputStream;
-import java.lang.ref.SoftReference;
+import sun.datatransfer.DataFlavorUtil;
+import sun.datatransfer.DesktopDatatransferService;
 
 import java.io.BufferedReader;
-import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.IOException;
-
-import java.net.URL;
-import java.net.MalformedURLException;
-
+import java.lang.ref.SoftReference;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -48,12 +41,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Properties;
 import java.util.Set;
 
-import sun.awt.AppContext;
-import sun.awt.datatransfer.DataTransferer;
-
 /**
  * The SystemFlavorMap is a configurable map between "natives" (Strings), which
  * correspond to platform-specific data formats, and "flavors" (DataFlavors),
@@ -191,16 +180,11 @@
 
     /**
      * Returns the default FlavorMap for this thread's ClassLoader.
+     *
      * @return the default FlavorMap for this thread's ClassLoader
      */
     public static FlavorMap getDefaultFlavorMap() {
-        AppContext context = AppContext.getAppContext();
-        FlavorMap fm = (FlavorMap) context.get(FLAVOR_MAP_KEY);
-        if (fm == null) {
-            fm = new SystemFlavorMap();
-            context.put(FLAVOR_MAP_KEY, fm);
-        }
-        return fm;
+        return DataFlavorUtil.getDesktopService().getFlavorMap(SystemFlavorMap::new);
     }
 
     private SystemFlavorMap() {
@@ -239,15 +223,17 @@
                         MimeType mime = new MimeType(value);
                         if ("text".equals(mime.getPrimaryType())) {
                             String charset = mime.getParameter("charset");
-                            if (DataTransferer.doesSubtypeSupportCharset(mime.getSubType(), charset))
+                            if (DataFlavorUtil.doesSubtypeSupportCharset(mime.getSubType(), charset))
                             {
                                 // We need to store the charset and eoln
                                 // parameters, if any, so that the
                                 // DataTransferer will have this information
                                 // for conversion into the native format.
-                                DataTransferer transferer = DataTransferer.getInstance();
-                                if (transferer != null) {
-                                    transferer.registerTextFlavorProperties(key, charset,
+                                DesktopDatatransferService desktopService =
+                                        DataFlavorUtil.getDesktopService();
+                                if (desktopService.isDesktopPresent()) {
+                                    desktopService.registerTextFlavorProperties(
+                                            key, charset,
                                             mime.getParameter("eoln"),
                                             mime.getParameter("terminators"));
                                 }
@@ -383,10 +369,10 @@
         LinkedHashSet<DataFlavor> flavors = getNativeToFlavor().get(nat);
 
         if (nat != null && !disabledMappingGenerationKeys.contains(nat)) {
-            DataTransferer transferer = DataTransferer.getInstance();
-            if (transferer != null) {
+            DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService();
+            if (desktopService.isDesktopPresent()) {
                 LinkedHashSet<DataFlavor> platformFlavors =
-                        transferer.getPlatformMappingsForNative(nat);
+                        desktopService.getPlatformMappingsForNative(nat);
                 if (!platformFlavors.isEmpty()) {
                     if (flavors != null) {
                         // Prepending the platform-specific mappings ensures
@@ -446,10 +432,10 @@
         LinkedHashSet<String> natives = getFlavorToNative().get(flav);
 
         if (flav != null && !disabledMappingGenerationKeys.contains(flav)) {
-            DataTransferer transferer = DataTransferer.getInstance();
-            if (transferer != null) {
+            DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService();
+            if (desktopService.isDesktopPresent()) {
                 LinkedHashSet<String> platformNatives =
-                    transferer.getPlatformMappingsForFlavor(flav);
+                        desktopService.getPlatformMappingsForFlavor(flav);
                 if (!platformNatives.isEmpty()) {
                     if (natives != null) {
                         // Prepend the platform-specific mappings to ensure
@@ -525,7 +511,7 @@
             // In this case we shouldn't synthesize a native for this flavor,
             // since its mappings were explicitly specified.
             retval = flavorToNativeLookup(flav, false);
-        } else if (DataTransferer.isFlavorCharsetTextType(flav)) {
+        } else if (DataFlavorUtil.isFlavorCharsetTextType(flav)) {
             retval = new LinkedHashSet<>(0);
 
             // For text/* flavors, flavor-to-native mappings specified in
@@ -553,7 +539,7 @@
                 // addUnencodedNativeForFlavor(), so they have lower priority.
                 retval.addAll(flavorToNativeLookup(flav, false));
             }
-        } else if (DataTransferer.isFlavorNoncharsetTextType(flav)) {
+        } else if (DataFlavorUtil.isFlavorNoncharsetTextType(flav)) {
             retval = getTextTypeToNative().get(flav.mimeType.getBaseType());
 
             if (retval == null || retval.isEmpty()) {
@@ -653,7 +639,7 @@
             // on load from flavormap.properties.
         }
 
-        if (DataTransferer.doesSubtypeSupportCharset(subType, null)) {
+        if (DataFlavorUtil.doesSubtypeSupportCharset(subType, null)) {
             if (TEXT_PLAIN_BASE_TYPE.equals(baseType))
             {
                 returnValue.add(DataFlavor.stringFlavor);
@@ -675,7 +661,7 @@
                 }
             }
 
-            for (String charset : DataTransferer.standardEncodings()) {
+            for (String charset : DataFlavorUtil.standardEncodings()) {
 
                 for (String encodedTextClass : ENCODED_TEXT_CLASSES) {
                     final String mimeType =
--- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Mon Jul 28 18:43:09 2014 +0400
+++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Mon Jul 28 19:02:56 2014 +0400
@@ -61,8 +61,6 @@
 import java.nio.charset.UnsupportedCharsetException;
 
 import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 
 import java.security.AccessController;
@@ -73,7 +71,7 @@
 
 import java.util.*;
 
-import sun.util.logging.PlatformLogger;
+import sun.datatransfer.DataFlavorUtil;
 
 import sun.awt.AppContext;
 import sun.awt.SunToolkit;
@@ -135,35 +133,6 @@
     public static final DataFlavor javaTextEncodingFlavor;
 
     /**
-     * Lazy initialization of Standard Encodings.
-     */
-    private static class StandardEncodingsHolder {
-        private static final SortedSet<String> standardEncodings = load();
-
-        private static SortedSet<String> load() {
-            final Comparator<String> comparator =
-                    new CharsetComparator(IndexedComparator.SELECT_WORST);
-            final SortedSet<String> tempSet = new TreeSet<>(comparator);
-            tempSet.add("US-ASCII");
-            tempSet.add("ISO-8859-1");
-            tempSet.add("UTF-8");
-            tempSet.add("UTF-16BE");
-            tempSet.add("UTF-16LE");
-            tempSet.add("UTF-16");
-            tempSet.add(Charset.defaultCharset().name());
-            return Collections.unmodifiableSortedSet(tempSet);
-        }
-    }
-
-    /**
-     * Tracks whether a particular text/* MIME type supports the charset
-     * parameter. The Map is initialized with all of the standard MIME types
-     * listed in the DataFlavor.selectBestTextFlavor method comment. Additional
-     * entries may be added during the life of the JRE for text/<other> types.
-     */
-    private static final Map<String, Boolean> textMIMESubtypeCharsetSupport;
-
-    /**
      * A collection of all natives listed in flavormap.properties with
      * a primary MIME type of "text".
      */
@@ -193,8 +162,6 @@
      */
     private static final String DATA_CONVERTER_KEY = "DATA_CONVERTER_KEY";
 
-    private static final PlatformLogger dtLog = PlatformLogger.getLogger("sun.awt.datatransfer.DataTransfer");
-
     static {
         DataFlavor tJavaTextEncodingFlavor = null;
         try {
@@ -202,24 +169,6 @@
         } catch (ClassNotFoundException cannotHappen) {
         }
         javaTextEncodingFlavor = tJavaTextEncodingFlavor;
-
-        Map<String, Boolean> tempMap = new HashMap<>(17);
-        tempMap.put("sgml", Boolean.TRUE);
-        tempMap.put("xml", Boolean.TRUE);
-        tempMap.put("html", Boolean.TRUE);
-        tempMap.put("enriched", Boolean.TRUE);
-        tempMap.put("richtext", Boolean.TRUE);
-        tempMap.put("uri-list", Boolean.TRUE);
-        tempMap.put("directory", Boolean.TRUE);
-        tempMap.put("css", Boolean.TRUE);
-        tempMap.put("calendar", Boolean.TRUE);
-        tempMap.put("plain", Boolean.TRUE);
-        tempMap.put("rtf", Boolean.FALSE);
-        tempMap.put("tab-separated-values", Boolean.FALSE);
-        tempMap.put("t140", Boolean.FALSE);
-        tempMap.put("rfc822-headers", Boolean.FALSE);
-        tempMap.put("parityfec", Boolean.FALSE);
-        textMIMESubtypeCharsetSupport = Collections.synchronizedMap(tempMap);
     }
 
     /**
@@ -232,171 +181,6 @@
     }
 
     /**
-     * Converts an arbitrary text encoding to its canonical name.
-     */
-    public static String canonicalName(String encoding) {
-        if (encoding == null) {
-            return null;
-        }
-        try {
-            return Charset.forName(encoding).name();
-        } catch (IllegalCharsetNameException icne) {
-            return encoding;
-        } catch (UnsupportedCharsetException uce) {
-            return encoding;
-        }
-    }
-
-    /**
-     * If the specified flavor is a text flavor which supports the "charset"
-     * parameter, then this method returns that parameter, or the default
-     * charset if no such parameter was specified at construction. For non-
-     * text DataFlavors, and for non-charset text flavors, this method returns
-     * null.
-     */
-    public static String getTextCharset(DataFlavor flavor) {
-        if (!isFlavorCharsetTextType(flavor)) {
-            return null;
-        }
-
-        String encoding = flavor.getParameter("charset");
-
-        return (encoding != null) ? encoding : Charset.defaultCharset().name();
-    }
-
-    /**
-     * Tests only whether the flavor's MIME type supports the charset
-     * parameter. Must only be called for flavors with a primary type of
-     * "text".
-     */
-    public static boolean doesSubtypeSupportCharset(DataFlavor flavor) {
-        if (dtLog.isLoggable(PlatformLogger.Level.FINE)) {
-            if (!"text".equals(flavor.getPrimaryType())) {
-                dtLog.fine("Assertion (\"text\".equals(flavor.getPrimaryType())) failed");
-            }
-        }
-
-        String subType = flavor.getSubType();
-        if (subType == null) {
-            return false;
-        }
-
-        Boolean support = textMIMESubtypeCharsetSupport.get(subType);
-
-        if (support != null) {
-            return support;
-        }
-
-        boolean ret_val = (flavor.getParameter("charset") != null);
-        textMIMESubtypeCharsetSupport.put(subType, ret_val);
-        return ret_val;
-    }
-    public static boolean doesSubtypeSupportCharset(String subType,
-                                                    String charset)
-    {
-        Boolean support = textMIMESubtypeCharsetSupport.get(subType);
-
-        if (support != null) {
-            return support;
-        }
-
-        boolean ret_val = (charset != null);
-        textMIMESubtypeCharsetSupport.put(subType, ret_val);
-        return ret_val;
-    }
-
-    /**
-     * Returns whether this flavor is a text type which supports the
-     * 'charset' parameter.
-     */
-    public static boolean isFlavorCharsetTextType(DataFlavor flavor) {
-        // Although stringFlavor doesn't actually support the charset
-        // parameter (because its primary MIME type is not "text"), it should
-        // be treated as though it does. stringFlavor is semantically
-        // equivalent to "text/plain" data.
-        if (DataFlavor.stringFlavor.equals(flavor)) {
-            return true;
-        }
-
-        if (!"text".equals(flavor.getPrimaryType()) ||
-            !doesSubtypeSupportCharset(flavor))
-        {
-            return false;
-        }
-
-        Class<?> rep_class = flavor.getRepresentationClass();
-
-        if (flavor.isRepresentationClassReader() ||
-            String.class.equals(rep_class) ||
-            flavor.isRepresentationClassCharBuffer() ||
-            char[].class.equals(rep_class))
-        {
-            return true;
-        }
-
-        if (!(flavor.isRepresentationClassInputStream() ||
-              flavor.isRepresentationClassByteBuffer() ||
-              byte[].class.equals(rep_class))) {
-            return false;
-        }
-
-        String charset = flavor.getParameter("charset");
-
-        return (charset != null)
-            ? DataTransferer.isEncodingSupported(charset)
-            : true; // null equals default encoding which is always supported
-    }
-
-    /**
-     * Returns whether this flavor is a text type which does not support the
-     * 'charset' parameter.
-     */
-    public static boolean isFlavorNoncharsetTextType(DataFlavor flavor) {
-        if (!"text".equals(flavor.getPrimaryType()) ||
-            doesSubtypeSupportCharset(flavor))
-        {
-            return false;
-        }
-
-        return (flavor.isRepresentationClassInputStream() ||
-                flavor.isRepresentationClassByteBuffer() ||
-                byte[].class.equals(flavor.getRepresentationClass()));
-    }
-
-    /**
-     * Determines whether this JRE can both encode and decode text in the
-     * specified encoding.
-     */
-    private static boolean isEncodingSupported(String encoding) {
-        if (encoding == null) {
-            return false;
-        }
-        try {
-            return Charset.isSupported(encoding);
-        } catch (IllegalCharsetNameException icne) {
-            return false;
-        }
-    }
-
-    /**
-     * Returns {@code true} if the given type is a java.rmi.Remote.
-     */
-    public static boolean isRemote(Class<?> type) {
-        return RMI.isRemote(type);
-    }
-
-    /**
-     * Returns an Iterator which traverses a SortedSet of Strings which are
-     * a total order of the standard character sets supported by the JRE. The
-     * ordering follows the same principles as DataFlavor.selectBestTextFlavor.
-     * So as to avoid loading all available character converters, optional,
-     * non-standard, character sets are not included.
-     */
-    public static Set <String> standardEncodings() {
-        return StandardEncodingsHolder.standardEncodings;
-    }
-
-    /**
      * Converts a FlavorMap to a FlavorTable.
      */
     public static FlavorTable adaptFlavorMap(final FlavorMap map) {
@@ -600,8 +384,7 @@
         indexMap.putAll(textPlainIndexMap);
 
         // Sort the map keys according to the formats preference order.
-        Comparator<Long> comparator =
-                new IndexOrderComparator(indexMap, IndexedComparator.SELECT_WORST);
+        Comparator<Long> comparator = DataFlavorUtil.getIndexOrderComparator(indexMap).reversed();
         SortedMap<Long, DataFlavor> sortedMap = new TreeMap<>(comparator);
         sortedMap.putAll(formatMap);
 
@@ -972,7 +755,7 @@
         // target format. Append terminating NUL bytes.
         if (stringSelectionHack ||
             (String.class.equals(flavor.getRepresentationClass()) &&
-             isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
+             DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
 
             String str = removeSuspectedData(flavor, contents, (String)obj);
 
@@ -983,7 +766,7 @@
         // Source data is a Reader. Convert to a String and recur. In the
         // future, we may want to rewrite this so that we encode on demand.
         } else if (flavor.isRepresentationClassReader()) {
-            if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
+            if (!(DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
                 throw new IOException
                     ("cannot transfer non-text data as Reader");
             }
@@ -1002,7 +785,7 @@
 
         // Source data is a CharBuffer. Convert to a String and recur.
         } else if (flavor.isRepresentationClassCharBuffer()) {
-            if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
+            if (!(DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
                 throw new IOException
                     ("cannot transfer non-text data as CharBuffer");
             }
@@ -1018,7 +801,7 @@
 
         // Source data is a char array. Convert to a String and recur.
         } else if (char[].class.equals(flavor.getRepresentationClass())) {
-            if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
+            if (!(DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
                 throw new IOException
                     ("cannot transfer non-text data as char array");
             }
@@ -1036,8 +819,8 @@
             byte[] bytes = new byte[size];
             buffer.get(bytes, 0, size);
 
-            if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
-                String sourceEncoding = DataTransferer.getTextCharset(flavor);
+            if (DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+                String sourceEncoding = DataFlavorUtil.getTextCharset(flavor);
                 return translateTransferableString(
                     new String(bytes, sourceEncoding),
                     format);
@@ -1051,8 +834,8 @@
         } else if (byte[].class.equals(flavor.getRepresentationClass())) {
             byte[] bytes = (byte[])obj;
 
-            if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
-                String sourceEncoding = DataTransferer.getTextCharset(flavor);
+            if (DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+                String sourceEncoding = DataFlavorUtil.getTextCharset(flavor);
                 return translateTransferableString(
                     new String(bytes, sourceEncoding),
                     format);
@@ -1155,9 +938,9 @@
                     } while (!eof);
                 }
 
-                if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+                if (DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
                     byte[] bytes = bos.toByteArray();
-                    String sourceEncoding = DataTransferer.getTextCharset(flavor);
+                    String sourceEncoding = DataFlavorUtil.getTextCharset(flavor);
                     return translateTransferableString(
                                new String(bytes, sourceEncoding),
                                format);
@@ -1166,14 +949,11 @@
             }
 
 
-
         // Source data is an RMI object
         } else if (flavor.isRepresentationClassRemote()) {
+            theByteArray = convertObjectToBytes(DataFlavorUtil.RMI.newMarshalledObject(obj));
 
-            Object mo = RMI.newMarshalledObject(obj);
-            theByteArray = convertObjectToBytes(mo);
-
-            // Source data is Serializable
+        // Source data is Serializable
         } else if (flavor.isRepresentationClassSerializable()) {
 
             theByteArray = convertObjectToBytes(obj);
@@ -1387,7 +1167,7 @@
             // 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)) {
+                   DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
 
             theObject = translateBytesToString(bytes, format, localeTransferable);
 
@@ -1401,9 +1181,8 @@
             }
             // 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");
+            if (!(DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
+                throw new IOException("cannot transfer non-text data as CharBuffer");
             }
 
             CharBuffer buffer = CharBuffer.wrap(
@@ -1414,7 +1193,7 @@
             // Target data is a char array. Recur to obtain String and convert to
             // char array.
         } else if (char[].class.equals(flavor.getRepresentationClass())) {
-            if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
+            if (!(DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
                 throw new IOException
                           ("cannot transfer non-text data as char array");
             }
@@ -1427,10 +1206,10 @@
             // terminators and search-and-replace EOLN, then reencode according to
             // the requested flavor.
         } else if (flavor.isRepresentationClassByteBuffer()) {
-            if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+            if (DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
                 bytes = translateBytesToString(
                     bytes, format, localeTransferable).getBytes(
-                        DataTransferer.getTextCharset(flavor)
+                        DataFlavorUtil.getTextCharset(flavor)
                     );
             }
 
@@ -1442,10 +1221,10 @@
             // terminators and search-and-replace EOLN, then reencode according to
             // the requested flavor.
         } else if (byte[].class.equals(flavor.getRepresentationClass())) {
-            if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+            if (DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
                 theObject = translateBytesToString(
                     bytes, format, localeTransferable
-                ).getBytes(DataTransferer.getTextCharset(flavor));
+                ).getBytes(DataFlavorUtil.getTextCharset(flavor));
             } else {
                 theObject = bytes;
             }
@@ -1462,9 +1241,9 @@
 
         } else if (flavor.isRepresentationClassRemote()) {
             try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
-                 ObjectInputStream ois = new ObjectInputStream(bais))
-            {
-                theObject = RMI.getMarshalledObject(ois.readObject());
+                 ObjectInputStream ois = new ObjectInputStream(bais)) {
+
+                theObject = DataFlavorUtil.RMI.getMarshalledObject(ois.readObject());
             } catch (Exception e) {
                 throw new IOException(e.getMessage());
             }
@@ -1529,7 +1308,7 @@
         // 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)) {
+                   DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
 
             return translateBytesToString(inputStreamToByteArray(str),
                 format, localeTransferable);
@@ -1554,7 +1333,7 @@
             // as "Unicode" (utf-16be). Then use an InputStreamReader to decode
             // back to chars on demand.
         } else if (flavor.isRepresentationClassReader()) {
-            if (!(isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
+            if (!(DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format))) {
                 throw new IOException
                           ("cannot transfer non-text data as Reader");
             }
@@ -1563,27 +1342,24 @@
                     str, DataFlavor.plainTextFlavor,
                     format, localeTransferable);
 
-            String unicode = DataTransferer.getTextCharset(DataFlavor.plainTextFlavor);
+            String unicode = DataFlavorUtil.getTextCharset(DataFlavor.plainTextFlavor);
 
             Reader reader = new InputStreamReader(is, unicode);
 
             theObject = constructFlavoredObject(reader, flavor, Reader.class);
             // Target data is a byte array
         } else if (byte[].class.equals(flavor.getRepresentationClass())) {
-            if(isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+            if (DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
                 theObject = translateBytesToString(inputStreamToByteArray(str), format, localeTransferable)
-                        .getBytes(DataTransferer.getTextCharset(flavor));
+                        .getBytes(DataFlavorUtil.getTextCharset(flavor));
             } else {
                 theObject = inputStreamToByteArray(str);
             }
             // Target data is an RMI object
         } else if (flavor.isRepresentationClassRemote()) {
-
-            try (ObjectInputStream ois =
-                     new ObjectInputStream(str))
-            {
-                theObject = RMI.getMarshalledObject(ois.readObject());
-            }catch (Exception e) {
+            try (ObjectInputStream ois = new ObjectInputStream(str)) {
+                theObject = DataFlavorUtil.RMI.getMarshalledObject(ois.readObject());
+            } catch (Exception e) {
                 throw new IOException(e.getMessage());
             }
 
@@ -1621,9 +1397,9 @@
         (InputStream str, DataFlavor flavor, long format,
          Transferable localeTransferable) throws IOException
     {
-        if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
+        if (DataFlavorUtil.isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
             str = new ReencodingInputStream
-                (str, format, DataTransferer.getTextCharset(flavor),
+                (str, format, DataFlavorUtil.getTextCharset(flavor),
                  localeTransferable);
         }
 
@@ -1865,8 +1641,7 @@
         byte[] bytes, String mimeType) throws IOException
     {
 
-        Iterator<ImageReader> readerIterator =
-            ImageIO.getImageReadersByMIMEType(mimeType);
+        Iterator<ImageReader> readerIterator = ImageIO.getImageReadersByMIMEType(mimeType);
 
         if (!readerIterator.hasNext()) {
             throw new IOException("No registered service provider can decode " +
@@ -1919,8 +1694,7 @@
       throws IOException {
         IOException originalIOE = null;
 
-        Iterator<ImageWriter> writerIterator =
-            ImageIO.getImageWritersByMIMEType(mimeType);
+        Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByMIMEType(mimeType);
 
         if (!writerIterator.hasNext()) {
             throw new IOException("No registered service provider can encode " +
@@ -1979,8 +1753,7 @@
                                               String mimeType)
         throws IOException {
 
-        Iterator<ImageWriter> writerIterator =
-            ImageIO.getImageWritersByMIMEType(mimeType);
+        Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByMIMEType(mimeType);
 
         ImageTypeSpecifier typeSpecifier =
             new ImageTypeSpecifier(renderedImage);
@@ -2163,8 +1936,7 @@
         }
     }
 
-    public abstract ToolkitThreadBlockedHandler
-        getToolkitThreadBlockedHandler();
+    public abstract ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler();
 
     /**
      * Helper function to reduce a Map with Long keys to a long array.
@@ -2189,8 +1961,7 @@
     public static DataFlavor[] setToSortedDataFlavorArray(Set<DataFlavor> flavorsSet) {
         DataFlavor[] flavors = new DataFlavor[flavorsSet.size()];
         flavorsSet.toArray(flavors);
-        final Comparator<DataFlavor> comparator =
-                new DataFlavorComparator(IndexedComparator.SELECT_WORST);
+        final Comparator<DataFlavor> comparator = DataFlavorUtil.getDataFlavorComparator().reversed();
         Arrays.sort(flavors, comparator);
         return flavors;
     }
@@ -2230,519 +2001,4 @@
     public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {
         return new LinkedHashSet<>();
     }
-
-    /**
-     * A Comparator which includes a helper function for comparing two Objects
-     * which are likely to be keys in the specified Map.
-     */
-    public abstract static class IndexedComparator<T> implements Comparator<T> {
-
-        /**
-         * The best Object (e.g., DataFlavor) will be the last in sequence.
-         */
-        public static final boolean SELECT_BEST = true;
-
-        /**
-         * The best Object (e.g., DataFlavor) will be the first in sequence.
-         */
-        public static final boolean SELECT_WORST = false;
-
-        final boolean order;
-
-        public IndexedComparator(boolean order) {
-            this.order = order;
-        }
-
-        /**
-         * Helper method to compare two objects by their Integer indices in the
-         * given map. If the map doesn't contain an entry for either of the
-         * objects, the fallback index will be used for the object instead.
-         *
-         * @param indexMap the map which maps objects into Integer indexes.
-         * @param obj1 the first object to be compared.
-         * @param obj2 the second object to be compared.
-         * @param fallbackIndex the Integer to be used as a fallback index.
-         * @return a negative integer, zero, or a positive integer as the
-         *             first object is mapped to a less, equal to, or greater
-         *             index than the second.
-         */
-        static <T> int compareIndices(Map<T, Integer> indexMap,
-                                      T obj1, T obj2,
-                                      Integer fallbackIndex) {
-            Integer index1 = indexMap.getOrDefault(obj1, fallbackIndex);
-            Integer index2 = indexMap.getOrDefault(obj2, fallbackIndex);
-            return index1.compareTo(index2);
-        }
-    }
-
-    /**
-     * An IndexedComparator which compares two String charsets. The comparison
-     * follows the rules outlined in DataFlavor.selectBestTextFlavor. In order
-     * to ensure that non-Unicode, non-ASCII, non-default charsets are sorted
-     * in alphabetical order, charsets are not automatically converted to their
-     * canonical forms.
-     */
-    public static class CharsetComparator extends IndexedComparator<String> {
-        private static final Map<String, Integer> charsets;
-
-        private static final Integer DEFAULT_CHARSET_INDEX = 2;
-        private static final Integer OTHER_CHARSET_INDEX = 1;
-        private static final Integer WORST_CHARSET_INDEX = 0;
-        private static final Integer UNSUPPORTED_CHARSET_INDEX = Integer.MIN_VALUE;
-
-        private static final String UNSUPPORTED_CHARSET = "UNSUPPORTED";
-
-        static {
-            Map<String, Integer> charsetsMap = new HashMap<>(8, 1.0f);
-
-            // we prefer Unicode charsets
-            charsetsMap.put(canonicalName("UTF-16LE"), 4);
-            charsetsMap.put(canonicalName("UTF-16BE"), 5);
-            charsetsMap.put(canonicalName("UTF-8"), 6);
-            charsetsMap.put(canonicalName("UTF-16"), 7);
-
-            // US-ASCII is the worst charset supported
-            charsetsMap.put(canonicalName("US-ASCII"), WORST_CHARSET_INDEX);
-
-            charsetsMap.putIfAbsent(Charset.defaultCharset().name(), DEFAULT_CHARSET_INDEX);
-
-            charsetsMap.put(UNSUPPORTED_CHARSET, UNSUPPORTED_CHARSET_INDEX);
-
-            charsets = Collections.unmodifiableMap(charsetsMap);
-        }
-
-        public CharsetComparator(boolean order) {
-            super(order);
-        }
-
-        /**
-         * Compares two String objects. Returns a negative integer, zero,
-         * or a positive integer as the first charset is worse than, equal to,
-         * or better than the second.
-         *
-         * @param obj1 the first charset to be compared
-         * @param obj2 the second charset to be compared
-         * @return a negative integer, zero, or a positive integer as the
-         *         first argument is worse, equal to, or better than the
-         *         second.
-         * @throws ClassCastException if either of the arguments is not
-         *         instance of String
-         * @throws NullPointerException if either of the arguments is
-         *         <code>null</code>.
-         */
-        public int compare(String obj1, String obj2) {
-            if (order == SELECT_BEST) {
-                return compareCharsets(obj1, obj2);
-            } else {
-                return compareCharsets(obj2, obj1);
-            }
-        }
-
-        /**
-         * Compares charsets. Returns a negative integer, zero, or a positive
-         * integer as the first charset is worse than, equal to, or better than
-         * the second.
-         * <p>
-         * Charsets are ordered according to the following rules:
-         * <ul>
-         * <li>All unsupported charsets are equal.
-         * <li>Any unsupported charset is worse than any supported charset.
-         * <li>Unicode charsets, such as "UTF-16", "UTF-8", "UTF-16BE" and
-         *     "UTF-16LE", are considered best.
-         * <li>After them, platform default charset is selected.
-         * <li>"US-ASCII" is the worst of supported charsets.
-         * <li>For all other supported charsets, the lexicographically less
-         *     one is considered the better.
-         * </ul>
-         *
-         * @param charset1 the first charset to be compared
-         * @param charset2 the second charset to be compared.
-         * @return a negative integer, zero, or a positive integer as the
-         *             first argument is worse, equal to, or better than the
-         *             second.
-         */
-        int compareCharsets(String charset1, String charset2) {
-            charset1 = getEncoding(charset1);
-            charset2 = getEncoding(charset2);
-
-            int comp = compareIndices(charsets, charset1, charset2,
-                                      OTHER_CHARSET_INDEX);
-
-            if (comp == 0) {
-                return charset2.compareTo(charset1);
-            }
-
-            return comp;
-        }
-
-        /**
-         * Returns encoding for the specified charset according to the
-         * following rules:
-         * <ul>
-         * <li>If the charset is <code>null</code>, then <code>null</code> will
-         *     be returned.
-         * <li>Iff the charset specifies an encoding unsupported by this JRE,
-         *     <code>UNSUPPORTED_CHARSET</code> will be returned.
-         * <li>If the charset specifies an alias name, the corresponding
-         *     canonical name will be returned iff the charset is a known
-         *     Unicode, ASCII, or default charset.
-         * </ul>
-         *
-         * @param charset the charset.
-         * @return an encoding for this charset.
-         */
-        static String getEncoding(String charset) {
-            if (charset == null) {
-                return null;
-            } else if (!DataTransferer.isEncodingSupported(charset)) {
-                return UNSUPPORTED_CHARSET;
-            } else {
-                // Only convert to canonical form if the charset is one
-                // of the charsets explicitly listed in the known charsets
-                // map. This will happen only for Unicode, ASCII, or default
-                // charsets.
-                String canonicalName = DataTransferer.canonicalName(charset);
-                return (charsets.containsKey(canonicalName))
-                    ? canonicalName
-                    : charset;
-            }
-        }
-    }
-
-    /**
-     * An IndexedComparator which compares two DataFlavors. For text flavors,
-     * the comparison follows the rules outlined in
-     * DataFlavor.selectBestTextFlavor. For non-text flavors, unknown
-     * application MIME types are preferred, followed by known
-     * application/x-java-* MIME types. Unknown application types are preferred
-     * because if the user provides his own data flavor, it will likely be the
-     * most descriptive one. For flavors which are otherwise equal, the
-     * flavors' string representation are compared in the alphabetical order.
-     */
-    public static class DataFlavorComparator extends IndexedComparator<DataFlavor> {
-
-        private final CharsetComparator charsetComparator;
-
-        private static final Map<String, Integer> exactTypes;
-        private static final Map<String, Integer> primaryTypes;
-        private static final Map<Class<?>, Integer> nonTextRepresentations;
-        private static final Map<String, Integer> textTypes;
-        private static final Map<Class<?>, Integer> decodedTextRepresentations;
-        private static final Map<Class<?>, Integer> encodedTextRepresentations;
-
-        private static final Integer UNKNOWN_OBJECT_LOSES = Integer.MIN_VALUE;
-        private static final Integer UNKNOWN_OBJECT_WINS = Integer.MAX_VALUE;
-
-        static {
-            {
-                Map<String, Integer> exactTypesMap = new HashMap<>(4, 1.0f);
-
-                // application/x-java-* MIME types
-                exactTypesMap.put("application/x-java-file-list", 0);
-                exactTypesMap.put("application/x-java-serialized-object", 1);
-                exactTypesMap.put("application/x-java-jvm-local-objectref", 2);
-                exactTypesMap.put("application/x-java-remote-object", 3);
-
-                exactTypes = Collections.unmodifiableMap(exactTypesMap);
-            }
-
-            {
-                Map<String, Integer> primaryTypesMap = new HashMap<>(1, 1.0f);
-
-                primaryTypesMap.put("application", 0);
-
-                primaryTypes = Collections.unmodifiableMap(primaryTypesMap);
-            }
-
-            {
-                Map<Class<?>, Integer> nonTextRepresentationsMap = new HashMap<>(3, 1.0f);
-
-                nonTextRepresentationsMap.put(java.io.InputStream.class, 0);
-                nonTextRepresentationsMap.put(java.io.Serializable.class, 1);
-
-                Class<?> remoteClass = RMI.remoteClass();
-                if (remoteClass != null) {
-                    nonTextRepresentationsMap.put(remoteClass, 2);
-                }
-
-                nonTextRepresentations = Collections.unmodifiableMap(nonTextRepresentationsMap);
-            }
-
-            {
-                Map<String, Integer> textTypesMap = new HashMap<>(16, 1.0f);
-
-                // plain text
-                textTypesMap.put("text/plain", 0);
-
-                // stringFlavor
-                textTypesMap.put("application/x-java-serialized-object", 1);
-
-                // misc
-                textTypesMap.put("text/calendar", 2);
-                textTypesMap.put("text/css", 3);
-                textTypesMap.put("text/directory", 4);
-                textTypesMap.put("text/parityfec", 5);
-                textTypesMap.put("text/rfc822-headers", 6);
-                textTypesMap.put("text/t140", 7);
-                textTypesMap.put("text/tab-separated-values", 8);
-                textTypesMap.put("text/uri-list", 9);
-
-                // enriched
-                textTypesMap.put("text/richtext", 10);
-                textTypesMap.put("text/enriched", 11);
-                textTypesMap.put("text/rtf", 12);
-
-                // markup
-                textTypesMap.put("text/html", 13);
-                textTypesMap.put("text/xml", 14);
-                textTypesMap.put("text/sgml", 15);
-
-                textTypes = Collections.unmodifiableMap(textTypesMap);
-            }
-
-            {
-                Map<Class<?>, Integer> decodedTextRepresentationsMap = new HashMap<>(4, 1.0f);
-
-                decodedTextRepresentationsMap.put(char[].class, 0);
-                decodedTextRepresentationsMap.put(CharBuffer.class, 1);
-                decodedTextRepresentationsMap.put(String.class, 2);
-                decodedTextRepresentationsMap.put(Reader.class, 3);
-
-                decodedTextRepresentations =
-                        Collections.unmodifiableMap(decodedTextRepresentationsMap);
-            }
-
-            {
-                Map<Class<?>, Integer> encodedTextRepresentationsMap = new HashMap<>(3, 1.0f);
-
-                encodedTextRepresentationsMap.put(byte[].class, 0);
-                encodedTextRepresentationsMap.put(ByteBuffer.class, 1);
-                encodedTextRepresentationsMap.put(InputStream.class, 2);
-
-                encodedTextRepresentations =
-                        Collections.unmodifiableMap(encodedTextRepresentationsMap);
-            }
-        }
-
-        public DataFlavorComparator() {
-            this(SELECT_BEST);
-        }
-
-        public DataFlavorComparator(boolean order) {
-            super(order);
-
-            charsetComparator = new CharsetComparator(order);
-        }
-
-        public int compare(DataFlavor obj1, DataFlavor obj2) {
-            DataFlavor flavor1 = order == SELECT_BEST ? obj1 : obj2;
-            DataFlavor flavor2 = order == SELECT_BEST ? obj2 : obj1;
-
-            if (flavor1.equals(flavor2)) {
-                return 0;
-            }
-
-            int comp = 0;
-
-            String primaryType1 = flavor1.getPrimaryType();
-            String subType1 = flavor1.getSubType();
-            String mimeType1 = primaryType1 + "/" + subType1;
-            Class<?> class1 = flavor1.getRepresentationClass();
-
-            String primaryType2 = flavor2.getPrimaryType();
-            String subType2 = flavor2.getSubType();
-            String mimeType2 = primaryType2 + "/" + subType2;
-            Class<?> class2 = flavor2.getRepresentationClass();
-
-            if (flavor1.isFlavorTextType() && flavor2.isFlavorTextType()) {
-                // First, compare MIME types
-                comp = compareIndices(textTypes, mimeType1, mimeType2,
-                                      UNKNOWN_OBJECT_LOSES);
-                if (comp != 0) {
-                    return comp;
-                }
-
-                // Only need to test one flavor because they both have the
-                // same MIME type. Also don't need to worry about accidentally
-                // passing stringFlavor because either
-                //   1. Both flavors are stringFlavor, in which case the
-                //      equality test at the top of the function succeeded.
-                //   2. Only one flavor is stringFlavor, in which case the MIME
-                //      type comparison returned a non-zero value.
-                if (doesSubtypeSupportCharset(flavor1)) {
-                    // Next, prefer the decoded text representations of Reader,
-                    // String, CharBuffer, and [C, in that order.
-                    comp = compareIndices(decodedTextRepresentations, class1,
-                                          class2, UNKNOWN_OBJECT_LOSES);
-                    if (comp != 0) {
-                        return comp;
-                    }
-
-                    // Next, compare charsets
-                    comp = charsetComparator.compareCharsets
-                        (DataTransferer.getTextCharset(flavor1),
-                         DataTransferer.getTextCharset(flavor2));
-                    if (comp != 0) {
-                        return comp;
-                    }
-                }
-
-                // Finally, prefer the encoded text representations of
-                // InputStream, ByteBuffer, and [B, in that order.
-                comp = compareIndices(encodedTextRepresentations, class1,
-                                      class2, UNKNOWN_OBJECT_LOSES);
-                if (comp != 0) {
-                    return comp;
-                }
-            } else {
-                // First, prefer application types.
-                comp = compareIndices(primaryTypes, primaryType1, primaryType2,
-                                      UNKNOWN_OBJECT_LOSES);
-                if (comp != 0) {
-                    return comp;
-                }
-
-                // Next, look for application/x-java-* types. Prefer unknown
-                // MIME types because if the user provides his own data flavor,
-                // it will likely be the most descriptive one.
-                comp = compareIndices(exactTypes, mimeType1, mimeType2,
-                                      UNKNOWN_OBJECT_WINS);
-                if (comp != 0) {
-                    return comp;
-                }
-
-                // Finally, prefer the representation classes of Remote,
-                // Serializable, and InputStream, in that order.
-                comp = compareIndices(nonTextRepresentations, class1, class2,
-                                      UNKNOWN_OBJECT_LOSES);
-                if (comp != 0) {
-                    return comp;
-                }
-            }
-
-            // The flavours are not equal but still not distinguishable.
-            // Compare String representations in alphabetical order
-            return flavor1.getMimeType().compareTo(flavor2.getMimeType());
-        }
-    }
-
-    /*
-     * Given the Map that maps objects to Integer indices and a boolean value,
-     * this Comparator imposes a direct or reverse order on set of objects.
-     * <p>
-     * If the specified boolean value is SELECT_BEST, the Comparator imposes the
-     * direct index-based order: an object A is greater than an object B if and
-     * only if the index of A is greater than the index of B. An object that
-     * doesn't have an associated index is less or equal than any other object.
-     * <p>
-     * If the specified boolean value is SELECT_WORST, the Comparator imposes the
-     * reverse index-based order: an object A is greater than an object B if and
-     * only if A is less than B with the direct index-based order.
-     */
-    public static class IndexOrderComparator extends IndexedComparator<Long> {
-        private final Map<Long, Integer> indexMap;
-        private static final Integer FALLBACK_INDEX = Integer.MIN_VALUE;
-
-        public IndexOrderComparator(Map<Long, Integer> indexMap, boolean order) {
-            super(order);
-            this.indexMap = indexMap;
-        }
-
-        public int compare(Long obj1, Long obj2) {
-            if (order == SELECT_WORST) {
-                return -compareIndices(indexMap, obj1, obj2, FALLBACK_INDEX);
-            } else {
-                return compareIndices(indexMap, obj1, obj2, FALLBACK_INDEX);
-            }
-        }
-    }
-
-    /**
-     * A class that provides access to java.rmi.Remote and java.rmi.MarshalledObject
-     * without creating a static dependency.
-     */
-    private static class RMI {
-        private static final Class<?> remoteClass = getClass("java.rmi.Remote");
-        private static final Class<?> marshallObjectClass =
-            getClass("java.rmi.MarshalledObject");
-        private static final Constructor<?> marshallCtor =
-            getConstructor(marshallObjectClass, Object.class);
-        private static final Method marshallGet =
-            getMethod(marshallObjectClass, "get");
-
-        private static Class<?> getClass(String name) {
-            try {
-                return Class.forName(name, true, null);
-            } catch (ClassNotFoundException e) {
-                return null;
-            }
-        }
-
-        private static Constructor<?> getConstructor(Class<?> c, Class<?>... types) {
-            try {
-                return (c == null) ? null : c.getDeclaredConstructor(types);
-            } catch (NoSuchMethodException x) {
-                throw new AssertionError(x);
-            }
-        }
-
-        private static Method getMethod(Class<?> c, String name, Class<?>... types) {
-            try {
-                return (c == null) ? null : c.getMethod(name, types);
-            } catch (NoSuchMethodException e) {
-                throw new AssertionError(e);
-            }
-        }
-
-        /**
-         * Returns {@code true} if the given class is java.rmi.Remote.
-         */
-        static boolean isRemote(Class<?> c) {
-            return (remoteClass == null) ? false : remoteClass.isAssignableFrom(c);
-        }
-
-        /**
-         * Returns java.rmi.Remote.class if RMI is present; otherwise {@code null}.
-         */
-        static Class<?> remoteClass() {
-            return remoteClass;
-        }
-
-        /**
-         * Returns a new MarshalledObject containing the serialized representation
-         * of the given object.
-         */
-        static Object newMarshalledObject(Object obj) throws IOException {
-            try {
-                return marshallCtor.newInstance(obj);
-            } catch (InstantiationException | IllegalAccessException x) {
-                throw new AssertionError(x);
-            } catch (InvocationTargetException  x) {
-                Throwable cause = x.getCause();
-                if (cause instanceof IOException)
-                    throw (IOException)cause;
-                throw new AssertionError(x);
-            }
-        }
-
-        /**
-         * Returns a new copy of the contained marshalled object.
-         */
-        static Object getMarshalledObject(Object obj)
-            throws IOException, ClassNotFoundException
-        {
-            try {
-                return marshallGet.invoke(obj);
-            } catch (IllegalAccessException x) {
-                throw new AssertionError(x);
-            } catch (InvocationTargetException x) {
-                Throwable cause = x.getCause();
-                if (cause instanceof IOException)
-                    throw (IOException)cause;
-                if (cause instanceof ClassNotFoundException)
-                    throw (ClassNotFoundException)cause;
-                throw new AssertionError(x);
-            }
-        }
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/awt/datatransfer/DesktopDatatransferServiceImpl.java	Mon Jul 28 19:02:56 2014 +0400
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.awt.datatransfer;
+
+import sun.awt.AppContext;
+import sun.datatransfer.DesktopDatatransferService;
+
+import java.awt.EventQueue;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.FlavorMap;
+import java.util.LinkedHashSet;
+import java.util.function.Supplier;
+
+/**
+ * Provides desktop services to the datatransfer module according to
+ * {@code DesktopDatatransferService} interface.
+ *
+ * @author Petr Pchelko
+ * @since 1.9
+ */
+public class DesktopDatatransferServiceImpl implements DesktopDatatransferService {
+
+    private static final Object FLAVOR_MAP_KEY = new Object();
+
+    @Override
+    public void invokeOnEventThread(Runnable r) {
+        EventQueue.invokeLater(r);
+    }
+
+    @Override
+    public String getDefaultUnicodeEncoding() {
+        DataTransferer dataTransferer = DataTransferer.getInstance();
+        if (dataTransferer != null) {
+            return dataTransferer.getDefaultUnicodeEncoding();
+        }
+        return null;
+    }
+
+    @Override
+    public FlavorMap getFlavorMap(Supplier<FlavorMap> supplier) {
+        AppContext context = AppContext.getAppContext();
+        FlavorMap fm = (FlavorMap) context.get(FLAVOR_MAP_KEY);
+        if (fm == null) {
+            fm = supplier.get();
+            context.put(FLAVOR_MAP_KEY, fm);
+        }
+        return fm;
+    }
+
+    @Override
+    public boolean isDesktopPresent() {
+        return true;
+    }
+
+    @Override
+    public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) {
+        DataTransferer instance = DataTransferer.getInstance();
+        return instance != null ? instance.getPlatformMappingsForNative(nat) : new LinkedHashSet<>();
+    }
+
+    @Override
+    public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {
+        DataTransferer instance = DataTransferer.getInstance();
+        return instance != null ? instance.getPlatformMappingsForFlavor(df) : new LinkedHashSet<>();
+    }
+
+    @Override
+    public void registerTextFlavorProperties(String nat, String charset, String eoln, String terminators) {
+        DataTransferer instance = DataTransferer.getInstance();
+        if (instance != null) {
+            instance.registerTextFlavorProperties(nat, charset, eoln, terminators);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/awt/datatransfer/META-INF/services/sun.datatransfer.DesktopDatatransferService	Mon Jul 28 19:02:56 2014 +0400
@@ -0,0 +1,1 @@
+sun.awt.datatransfer.DesktopDatatransferServiceImpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/datatransfer/DataFlavorUtil.java	Mon Jul 28 19:02:56 2014 +0400
@@ -0,0 +1,832 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.datatransfer;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.FlavorMap;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.function.Supplier;
+
+
+/**
+ * Utility class with different datatransfer helper functions
+ *
+ * @see 1.9
+ */
+public class DataFlavorUtil {
+
+    private DataFlavorUtil() {
+        // Avoid instantiation
+    }
+
+    private static Comparator<String> getCharsetComparator() {
+       return CharsetComparator.INSTANCE;
+    }
+
+    public static Comparator<DataFlavor> getDataFlavorComparator() {
+       return DataFlavorComparator.INSTANCE;
+    }
+
+    public static Comparator<Long> getIndexOrderComparator(Map<Long, Integer> indexMap) {
+        return new IndexOrderComparator(indexMap);
+    }
+
+    public static Comparator<DataFlavor> getTextFlavorComparator() {
+        return TextFlavorComparator.INSTANCE;
+    }
+
+    /**
+     * Tracks whether a particular text/* MIME type supports the charset
+     * parameter. The Map is initialized with all of the standard MIME types
+     * listed in the DataFlavor.selectBestTextFlavor method comment. Additional
+     * entries may be added during the life of the JRE for text/<other> types.
+     */
+    private static final Map<String, Boolean> textMIMESubtypeCharsetSupport;
+
+    static {
+        Map<String, Boolean> tempMap = new HashMap<>(17);
+        tempMap.put("sgml", Boolean.TRUE);
+        tempMap.put("xml", Boolean.TRUE);
+        tempMap.put("html", Boolean.TRUE);
+        tempMap.put("enriched", Boolean.TRUE);
+        tempMap.put("richtext", Boolean.TRUE);
+        tempMap.put("uri-list", Boolean.TRUE);
+        tempMap.put("directory", Boolean.TRUE);
+        tempMap.put("css", Boolean.TRUE);
+        tempMap.put("calendar", Boolean.TRUE);
+        tempMap.put("plain", Boolean.TRUE);
+        tempMap.put("rtf", Boolean.FALSE);
+        tempMap.put("tab-separated-values", Boolean.FALSE);
+        tempMap.put("t140", Boolean.FALSE);
+        tempMap.put("rfc822-headers", Boolean.FALSE);
+        tempMap.put("parityfec", Boolean.FALSE);
+        textMIMESubtypeCharsetSupport = Collections.synchronizedMap(tempMap);
+    }
+
+    /**
+     * Lazy initialization of Standard Encodings.
+     */
+    private static class StandardEncodingsHolder {
+        private static final SortedSet<String> standardEncodings = load();
+
+        private static SortedSet<String> load() {
+            final SortedSet<String> tempSet = new TreeSet<>(getCharsetComparator().reversed());
+            tempSet.add("US-ASCII");
+            tempSet.add("ISO-8859-1");
+            tempSet.add("UTF-8");
+            tempSet.add("UTF-16BE");
+            tempSet.add("UTF-16LE");
+            tempSet.add("UTF-16");
+            tempSet.add(Charset.defaultCharset().name());
+            return Collections.unmodifiableSortedSet(tempSet);
+        }
+    }
+
+    /**
+     * Returns a {@code SortedSet} of Strings which are a total order of the standard
+     * character sets supported by the JRE. The ordering follows the same principles as
+     * {@link java.awt.datatransfer.DataFlavor#selectBestTextFlavor(java.awt.datatransfer.DataFlavor[])}.
+     * So as to avoid loading all available character converters, optional, non-standard,
+     * character sets are not included.
+     */
+    public static Set<String> standardEncodings() {
+        return StandardEncodingsHolder.standardEncodings;
+    }
+
+    /**
+     * Converts an arbitrary text encoding to its canonical name.
+     */
+    public static String canonicalName(String encoding) {
+        if (encoding == null) {
+            return null;
+        }
+        try {
+            return Charset.forName(encoding).name();
+        } catch (IllegalCharsetNameException icne) {
+            return encoding;
+        } catch (UnsupportedCharsetException uce) {
+            return encoding;
+        }
+    }
+
+    /**
+     * Tests only whether the flavor's MIME type supports the charset
+     * parameter. Must only be called for flavors with a primary type of
+     * "text".
+     */
+    public static boolean doesSubtypeSupportCharset(DataFlavor flavor) {
+        String subType = flavor.getSubType();
+        if (subType == null) {
+            return false;
+        }
+
+        Boolean support = textMIMESubtypeCharsetSupport.get(subType);
+
+        if (support != null) {
+            return support;
+        }
+
+        boolean ret_val = (flavor.getParameter("charset") != null);
+        textMIMESubtypeCharsetSupport.put(subType, ret_val);
+        return ret_val;
+    }
+    public static boolean doesSubtypeSupportCharset(String subType,
+                                                    String charset)
+    {
+        Boolean support = textMIMESubtypeCharsetSupport.get(subType);
+
+        if (support != null) {
+            return support;
+        }
+
+        boolean ret_val = (charset != null);
+        textMIMESubtypeCharsetSupport.put(subType, ret_val);
+        return ret_val;
+    }
+
+
+    /**
+     * Returns whether this flavor is a text type which supports the
+     * 'charset' parameter.
+     */
+    public static boolean isFlavorCharsetTextType(DataFlavor flavor) {
+        // Although stringFlavor doesn't actually support the charset
+        // parameter (because its primary MIME type is not "text"), it should
+        // be treated as though it does. stringFlavor is semantically
+        // equivalent to "text/plain" data.
+        if (DataFlavor.stringFlavor.equals(flavor)) {
+            return true;
+        }
+
+        if (!"text".equals(flavor.getPrimaryType()) ||
+                !doesSubtypeSupportCharset(flavor))
+        {
+            return false;
+        }
+
+        Class<?> rep_class = flavor.getRepresentationClass();
+
+        if (flavor.isRepresentationClassReader() ||
+                String.class.equals(rep_class) ||
+                flavor.isRepresentationClassCharBuffer() ||
+                char[].class.equals(rep_class))
+        {
+            return true;
+        }
+
+        if (!(flavor.isRepresentationClassInputStream() ||
+                flavor.isRepresentationClassByteBuffer() ||
+                byte[].class.equals(rep_class))) {
+            return false;
+        }
+
+        String charset = flavor.getParameter("charset");
+
+        // null equals default encoding which is always supported
+        return (charset == null) || isEncodingSupported(charset);
+    }
+
+    /**
+     * Returns whether this flavor is a text type which does not support the
+     * 'charset' parameter.
+     */
+    public static boolean isFlavorNoncharsetTextType(DataFlavor flavor) {
+        if (!"text".equals(flavor.getPrimaryType()) || doesSubtypeSupportCharset(flavor)) {
+            return false;
+        }
+
+        return (flavor.isRepresentationClassInputStream() ||
+                flavor.isRepresentationClassByteBuffer() ||
+                byte[].class.equals(flavor.getRepresentationClass()));
+    }
+
+    /**
+     * If the specified flavor is a text flavor which supports the "charset"
+     * parameter, then this method returns that parameter, or the default
+     * charset if no such parameter was specified at construction. For non-
+     * text DataFlavors, and for non-charset text flavors, this method returns
+     * null.
+     */
+    public static String getTextCharset(DataFlavor flavor) {
+        if (!isFlavorCharsetTextType(flavor)) {
+            return null;
+        }
+
+        String encoding = flavor.getParameter("charset");
+
+        return (encoding != null) ? encoding : Charset.defaultCharset().name();
+    }
+
+    /**
+     * Determines whether this JRE can both encode and decode text in the
+     * specified encoding.
+     */
+    private static boolean isEncodingSupported(String encoding) {
+        if (encoding == null) {
+            return false;
+        }
+        try {
+            return Charset.isSupported(encoding);
+        } catch (IllegalCharsetNameException icne) {
+            return false;
+        }
+    }
+
+    /**
+     * Helper method to compare two objects by their Integer indices in the
+     * given map. If the map doesn't contain an entry for either of the
+     * objects, the fallback index will be used for the object instead.
+     *
+     * @param indexMap the map which maps objects into Integer indexes.
+     * @param obj1 the first object to be compared.
+     * @param obj2 the second object to be compared.
+     * @param fallbackIndex the Integer to be used as a fallback index.
+     * @return a negative integer, zero, or a positive integer as the
+     *             first object is mapped to a less, equal to, or greater
+     *             index than the second.
+     */
+    static <T> int compareIndices(Map<T, Integer> indexMap,
+                                  T obj1, T obj2,
+                                  Integer fallbackIndex) {
+        Integer index1 = indexMap.getOrDefault(obj1, fallbackIndex);
+        Integer index2 = indexMap.getOrDefault(obj2, fallbackIndex);
+        return index1.compareTo(index2);
+    }
+
+    /**
+     * An IndexedComparator which compares two String charsets. The comparison
+     * follows the rules outlined in DataFlavor.selectBestTextFlavor. In order
+     * to ensure that non-Unicode, non-ASCII, non-default charsets are sorted
+     * in alphabetical order, charsets are not automatically converted to their
+     * canonical forms.
+     */
+    private static class CharsetComparator implements Comparator<String> {
+        static final CharsetComparator INSTANCE = new CharsetComparator();
+
+        private static final Map<String, Integer> charsets;
+
+        private static final Integer DEFAULT_CHARSET_INDEX = 2;
+        private static final Integer OTHER_CHARSET_INDEX = 1;
+        private static final Integer WORST_CHARSET_INDEX = 0;
+        private static final Integer UNSUPPORTED_CHARSET_INDEX = Integer.MIN_VALUE;
+
+        private static final String UNSUPPORTED_CHARSET = "UNSUPPORTED";
+
+        static {
+            Map<String, Integer> charsetsMap = new HashMap<>(8, 1.0f);
+
+            // we prefer Unicode charsets
+            charsetsMap.put(canonicalName("UTF-16LE"), 4);
+            charsetsMap.put(canonicalName("UTF-16BE"), 5);
+            charsetsMap.put(canonicalName("UTF-8"), 6);
+            charsetsMap.put(canonicalName("UTF-16"), 7);
+
+            // US-ASCII is the worst charset supported
+            charsetsMap.put(canonicalName("US-ASCII"), WORST_CHARSET_INDEX);
+
+            charsetsMap.putIfAbsent(Charset.defaultCharset().name(), DEFAULT_CHARSET_INDEX);
+
+            charsetsMap.put(UNSUPPORTED_CHARSET, UNSUPPORTED_CHARSET_INDEX);
+
+            charsets = Collections.unmodifiableMap(charsetsMap);
+        }
+
+        /**
+         * Compares charsets. Returns a negative integer, zero, or a positive
+         * integer as the first charset is worse than, equal to, or better than
+         * the second.
+         * <p>
+         * Charsets are ordered according to the following rules:
+         * <ul>
+         * <li>All unsupported charsets are equal.
+         * <li>Any unsupported charset is worse than any supported charset.
+         * <li>Unicode charsets, such as "UTF-16", "UTF-8", "UTF-16BE" and
+         *     "UTF-16LE", are considered best.
+         * <li>After them, platform default charset is selected.
+         * <li>"US-ASCII" is the worst of supported charsets.
+         * <li>For all other supported charsets, the lexicographically less
+         *     one is considered the better.
+         * </ul>
+         *
+         * @param charset1 the first charset to be compared
+         * @param charset2 the second charset to be compared.
+         * @return a negative integer, zero, or a positive integer as the
+         *             first argument is worse, equal to, or better than the
+         *             second.
+         */
+        public int compare(String charset1, String charset2) {
+            charset1 = getEncoding(charset1);
+            charset2 = getEncoding(charset2);
+
+            int comp = compareIndices(charsets, charset1, charset2, OTHER_CHARSET_INDEX);
+
+            if (comp == 0) {
+                return charset2.compareTo(charset1);
+            }
+
+            return comp;
+        }
+
+        /**
+         * Returns encoding for the specified charset according to the
+         * following rules:
+         * <ul>
+         * <li>If the charset is <code>null</code>, then <code>null</code> will
+         *     be returned.
+         * <li>Iff the charset specifies an encoding unsupported by this JRE,
+         *     <code>UNSUPPORTED_CHARSET</code> will be returned.
+         * <li>If the charset specifies an alias name, the corresponding
+         *     canonical name will be returned iff the charset is a known
+         *     Unicode, ASCII, or default charset.
+         * </ul>
+         *
+         * @param charset the charset.
+         * @return an encoding for this charset.
+         */
+        static String getEncoding(String charset) {
+            if (charset == null) {
+                return null;
+            } else if (!isEncodingSupported(charset)) {
+                return UNSUPPORTED_CHARSET;
+            } else {
+                // Only convert to canonical form if the charset is one
+                // of the charsets explicitly listed in the known charsets
+                // map. This will happen only for Unicode, ASCII, or default
+                // charsets.
+                String canonicalName = canonicalName(charset);
+                return (charsets.containsKey(canonicalName))
+                        ? canonicalName
+                        : charset;
+            }
+        }
+    }
+
+    /**
+     * An IndexedComparator which compares two DataFlavors. For text flavors,
+     * the comparison follows the rules outlined in
+     * DataFlavor.selectBestTextFlavor. For non-text flavors, unknown
+     * application MIME types are preferred, followed by known
+     * application/x-java-* MIME types. Unknown application types are preferred
+     * because if the user provides his own data flavor, it will likely be the
+     * most descriptive one. For flavors which are otherwise equal, the
+     * flavors' string representation are compared in the alphabetical order.
+     */
+    private static class DataFlavorComparator implements Comparator<DataFlavor> {
+
+        static final DataFlavorComparator INSTANCE = new DataFlavorComparator();
+
+        private static final Map<String, Integer> exactTypes;
+        private static final Map<String, Integer> primaryTypes;
+        private static final Map<Class<?>, Integer> nonTextRepresentations;
+        private static final Map<String, Integer> textTypes;
+        private static final Map<Class<?>, Integer> decodedTextRepresentations;
+        private static final Map<Class<?>, Integer> encodedTextRepresentations;
+
+        private static final Integer UNKNOWN_OBJECT_LOSES = Integer.MIN_VALUE;
+        private static final Integer UNKNOWN_OBJECT_WINS = Integer.MAX_VALUE;
+
+        static {
+            {
+                Map<String, Integer> exactTypesMap = new HashMap<>(4, 1.0f);
+
+                // application/x-java-* MIME types
+                exactTypesMap.put("application/x-java-file-list", 0);
+                exactTypesMap.put("application/x-java-serialized-object", 1);
+                exactTypesMap.put("application/x-java-jvm-local-objectref", 2);
+                exactTypesMap.put("application/x-java-remote-object", 3);
+
+                exactTypes = Collections.unmodifiableMap(exactTypesMap);
+            }
+
+            {
+                Map<String, Integer> primaryTypesMap = new HashMap<>(1, 1.0f);
+
+                primaryTypesMap.put("application", 0);
+
+                primaryTypes = Collections.unmodifiableMap(primaryTypesMap);
+            }
+
+            {
+                Map<Class<?>, Integer> nonTextRepresentationsMap = new HashMap<>(3, 1.0f);
+
+                nonTextRepresentationsMap.put(java.io.InputStream.class, 0);
+                nonTextRepresentationsMap.put(java.io.Serializable.class, 1);
+
+                nonTextRepresentationsMap.put(RMI.remoteClass(), 2);
+
+                nonTextRepresentations = Collections.unmodifiableMap(nonTextRepresentationsMap);
+            }
+
+            {
+                Map<String, Integer> textTypesMap = new HashMap<>(16, 1.0f);
+
+                // plain text
+                textTypesMap.put("text/plain", 0);
+
+                // stringFlavor
+                textTypesMap.put("application/x-java-serialized-object", 1);
+
+                // misc
+                textTypesMap.put("text/calendar", 2);
+                textTypesMap.put("text/css", 3);
+                textTypesMap.put("text/directory", 4);
+                textTypesMap.put("text/parityfec", 5);
+                textTypesMap.put("text/rfc822-headers", 6);
+                textTypesMap.put("text/t140", 7);
+                textTypesMap.put("text/tab-separated-values", 8);
+                textTypesMap.put("text/uri-list", 9);
+
+                // enriched
+                textTypesMap.put("text/richtext", 10);
+                textTypesMap.put("text/enriched", 11);
+                textTypesMap.put("text/rtf", 12);
+
+                // markup
+                textTypesMap.put("text/html", 13);
+                textTypesMap.put("text/xml", 14);
+                textTypesMap.put("text/sgml", 15);
+
+                textTypes = Collections.unmodifiableMap(textTypesMap);
+            }
+
+            {
+                Map<Class<?>, Integer> decodedTextRepresentationsMap = new HashMap<>(4, 1.0f);
+
+                decodedTextRepresentationsMap.put(char[].class, 0);
+                decodedTextRepresentationsMap.put(CharBuffer.class, 1);
+                decodedTextRepresentationsMap.put(String.class, 2);
+                decodedTextRepresentationsMap.put(Reader.class, 3);
+
+                decodedTextRepresentations =
+                        Collections.unmodifiableMap(decodedTextRepresentationsMap);
+            }
+
+            {
+                Map<Class<?>, Integer> encodedTextRepresentationsMap = new HashMap<>(3, 1.0f);
+
+                encodedTextRepresentationsMap.put(byte[].class, 0);
+                encodedTextRepresentationsMap.put(ByteBuffer.class, 1);
+                encodedTextRepresentationsMap.put(InputStream.class, 2);
+
+                encodedTextRepresentations =
+                        Collections.unmodifiableMap(encodedTextRepresentationsMap);
+            }
+        }
+
+
+        public int compare(DataFlavor flavor1, DataFlavor flavor2) {
+            if (flavor1.equals(flavor2)) {
+                return 0;
+            }
+
+            int comp;
+
+            String primaryType1 = flavor1.getPrimaryType();
+            String subType1 = flavor1.getSubType();
+            String mimeType1 = primaryType1 + "/" + subType1;
+            Class<?> class1 = flavor1.getRepresentationClass();
+
+            String primaryType2 = flavor2.getPrimaryType();
+            String subType2 = flavor2.getSubType();
+            String mimeType2 = primaryType2 + "/" + subType2;
+            Class<?> class2 = flavor2.getRepresentationClass();
+
+            if (flavor1.isFlavorTextType() && flavor2.isFlavorTextType()) {
+                // First, compare MIME types
+                comp = compareIndices(textTypes, mimeType1, mimeType2, UNKNOWN_OBJECT_LOSES);
+                if (comp != 0) {
+                    return comp;
+                }
+
+                // Only need to test one flavor because they both have the
+                // same MIME type. Also don't need to worry about accidentally
+                // passing stringFlavor because either
+                //   1. Both flavors are stringFlavor, in which case the
+                //      equality test at the top of the function succeeded.
+                //   2. Only one flavor is stringFlavor, in which case the MIME
+                //      type comparison returned a non-zero value.
+                if (doesSubtypeSupportCharset(flavor1)) {
+                    // Next, prefer the decoded text representations of Reader,
+                    // String, CharBuffer, and [C, in that order.
+                    comp = compareIndices(decodedTextRepresentations, class1,
+                            class2, UNKNOWN_OBJECT_LOSES);
+                    if (comp != 0) {
+                        return comp;
+                    }
+
+                    // Next, compare charsets
+                    comp = CharsetComparator.INSTANCE.compare(getTextCharset(flavor1),
+                            getTextCharset(flavor2));
+                    if (comp != 0) {
+                        return comp;
+                    }
+                }
+
+                // Finally, prefer the encoded text representations of
+                // InputStream, ByteBuffer, and [B, in that order.
+                comp = compareIndices(encodedTextRepresentations, class1,
+                        class2, UNKNOWN_OBJECT_LOSES);
+                if (comp != 0) {
+                    return comp;
+                }
+            } else {
+                // First, prefer application types.
+                comp = compareIndices(primaryTypes, primaryType1, primaryType2,
+                        UNKNOWN_OBJECT_LOSES);
+                if (comp != 0) {
+                    return comp;
+                }
+
+                // Next, look for application/x-java-* types. Prefer unknown
+                // MIME types because if the user provides his own data flavor,
+                // it will likely be the most descriptive one.
+                comp = compareIndices(exactTypes, mimeType1, mimeType2,
+                        UNKNOWN_OBJECT_WINS);
+                if (comp != 0) {
+                    return comp;
+                }
+
+                // Finally, prefer the representation classes of Remote,
+                // Serializable, and InputStream, in that order.
+                comp = compareIndices(nonTextRepresentations, class1, class2,
+                        UNKNOWN_OBJECT_LOSES);
+                if (comp != 0) {
+                    return comp;
+                }
+            }
+
+            // The flavours are not equal but still not distinguishable.
+            // Compare String representations in alphabetical order
+            return flavor1.getMimeType().compareTo(flavor2.getMimeType());
+        }
+    }
+
+    /*
+     * Given the Map that maps objects to Integer indices and a boolean value,
+     * this Comparator imposes a direct or reverse order on set of objects.
+     * <p>
+     * If the specified boolean value is SELECT_BEST, the Comparator imposes the
+     * direct index-based order: an object A is greater than an object B if and
+     * only if the index of A is greater than the index of B. An object that
+     * doesn't have an associated index is less or equal than any other object.
+     * <p>
+     * If the specified boolean value is SELECT_WORST, the Comparator imposes the
+     * reverse index-based order: an object A is greater than an object B if and
+     * only if A is less than B with the direct index-based order.
+     */
+    private static class IndexOrderComparator implements Comparator<Long> {
+        private final Map<Long, Integer> indexMap;
+        private static final Integer FALLBACK_INDEX = Integer.MIN_VALUE;
+
+        public IndexOrderComparator(Map<Long, Integer> indexMap) {
+            this.indexMap = indexMap;
+        }
+
+        public int compare(Long obj1, Long obj2) {
+            return compareIndices(indexMap, obj1, obj2, FALLBACK_INDEX);
+        }
+    }
+
+    private static class TextFlavorComparator extends DataFlavorComparator {
+
+        static final TextFlavorComparator INSTANCE = new TextFlavorComparator();
+        /**
+         * Compares two <code>DataFlavor</code> objects. Returns a negative
+         * integer, zero, or a positive integer as the first
+         * <code>DataFlavor</code> is worse than, equal to, or better than the
+         * second.
+         * <p>
+         * <code>DataFlavor</code>s are ordered according to the rules outlined
+         * for <code>selectBestTextFlavor</code>.
+         *
+         * @param flavor1 the first <code>DataFlavor</code> to be compared
+         * @param flavor2 the second <code>DataFlavor</code> to be compared
+         * @return a negative integer, zero, or a positive integer as the first
+         *         argument is worse, equal to, or better than the second
+         * @throws ClassCastException if either of the arguments is not an
+         *         instance of <code>DataFlavor</code>
+         * @throws NullPointerException if either of the arguments is
+         *         <code>null</code>
+         *
+         * @see java.awt.datatransfer.DataFlavor#selectBestTextFlavor
+         */
+        public int compare(DataFlavor flavor1, DataFlavor flavor2) {
+            if (flavor1.isFlavorTextType()) {
+                if (flavor2.isFlavorTextType()) {
+                    return super.compare(flavor1, flavor2);
+                } else {
+                    return 1;
+                }
+            } else if (flavor2.isFlavorTextType()) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    /**
+     * A fallback implementation of {@link sun.datatransfer.DesktopDatatransferService}
+     * used if there is no desktop.
+     */
+    private static final class DefaultDesktopDatatransferService implements DesktopDatatransferService {
+        static final DesktopDatatransferService INSTANCE = getDesktopService();
+
+        private static DesktopDatatransferService getDesktopService() {
+            ServiceLoader<DesktopDatatransferService> loader =
+                    ServiceLoader.load(DesktopDatatransferService.class, null);
+            Iterator<DesktopDatatransferService> iterator = loader.iterator();
+            if (iterator.hasNext()) {
+                return iterator.next();
+            } else {
+                return new DefaultDesktopDatatransferService();
+            }
+        }
+
+        /**
+         * System singleton FlavorTable.
+         * Only used if there is no desktop
+         * to provide an appropriate FlavorMap.
+         */
+        private volatile FlavorMap flavorMap;
+
+        @Override
+        public void invokeOnEventThread(Runnable r) {
+            r.run();
+        }
+
+        @Override
+        public String getDefaultUnicodeEncoding() {
+            return StandardCharsets.UTF_8.name();
+        }
+
+        @Override
+        public FlavorMap getFlavorMap(Supplier<FlavorMap> supplier) {
+            FlavorMap map = flavorMap;
+            if (map == null) {
+                synchronized (this) {
+                    map = flavorMap;
+                    if (map == null) {
+                        flavorMap = map = supplier.get();
+                    }
+                }
+            }
+            return map;
+        }
+
+        @Override
+        public boolean isDesktopPresent() {
+            return false;
+        }
+
+        @Override
+        public LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat) {
+            return new LinkedHashSet<>();
+        }
+
+        @Override
+        public LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df) {
+            return new LinkedHashSet<>();
+        }
+
+        @Override
+        public void registerTextFlavorProperties(String nat, String charset,
+                                                 String eoln, String terminators) {
+            // Not needed if desktop module is absent
+        }
+    }
+
+    public static DesktopDatatransferService getDesktopService() {
+        return DefaultDesktopDatatransferService.INSTANCE;
+    }
+
+    /**
+     * A class that provides access to java.rmi.Remote and java.rmi.MarshalledObject
+     * without creating a static dependency.
+     */
+    public static class RMI {
+        private static final Class<?> remoteClass = getClass("java.rmi.Remote");
+        private static final Class<?> marshallObjectClass = getClass("java.rmi.MarshalledObject");
+        private static final Constructor<?> marshallCtor = getConstructor(marshallObjectClass, Object.class);
+        private static final Method marshallGet = getMethod(marshallObjectClass, "get");
+
+        private static Class<?> getClass(String name) {
+            try {
+                return Class.forName(name, true, null);
+            } catch (ClassNotFoundException e) {
+                return null;
+            }
+        }
+
+        private static Constructor<?> getConstructor(Class<?> c, Class<?>... types) {
+            try {
+                return (c == null) ? null : c.getDeclaredConstructor(types);
+            } catch (NoSuchMethodException x) {
+                throw new AssertionError(x);
+            }
+        }
+
+        private static Method getMethod(Class<?> c, String name, Class<?>... types) {
+            try {
+                return (c == null) ? null : c.getMethod(name, types);
+            } catch (NoSuchMethodException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        /**
+         * Returns java.rmi.Remote.class if RMI is present; otherwise {@code null}.
+         */
+        static Class<?> remoteClass() {
+            return remoteClass;
+        }
+
+        /**
+         * Returns {@code true} if the given class is java.rmi.Remote.
+         */
+        public static boolean isRemote(Class<?> c) {
+            return (remoteClass != null) && remoteClass.isAssignableFrom(c);
+        }
+
+        /**
+         * Returns a new MarshalledObject containing the serialized representation
+         * of the given object.
+         */
+        public static Object newMarshalledObject(Object obj) throws IOException {
+            try {
+                return marshallCtor == null ? null : marshallCtor.newInstance(obj);
+            } catch (InstantiationException | IllegalAccessException x) {
+                throw new AssertionError(x);
+            } catch (InvocationTargetException x) {
+                Throwable cause = x.getCause();
+                if (cause instanceof IOException)
+                    throw (IOException) cause;
+                throw new AssertionError(x);
+            }
+        }
+
+        /**
+         * Returns a new copy of the contained marshalled object.
+         */
+        public static Object getMarshalledObject(Object obj)
+                throws IOException, ClassNotFoundException {
+            try {
+                return marshallGet == null ? null : marshallGet.invoke(obj);
+            } catch (IllegalAccessException x) {
+                throw new AssertionError(x);
+            } catch (InvocationTargetException x) {
+                Throwable cause = x.getCause();
+                if (cause instanceof IOException)
+                    throw (IOException) cause;
+                if (cause instanceof ClassNotFoundException)
+                    throw (ClassNotFoundException) cause;
+                throw new AssertionError(x);
+            }
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/datatransfer/DesktopDatatransferService.java	Mon Jul 28 19:02:56 2014 +0400
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.datatransfer;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.FlavorMap;
+import java.util.LinkedHashSet;
+import java.util.function.Supplier;
+
+/**
+ * Contains services which desktop provides to the datatransfer system
+ * to enrich it's functionality
+ *
+ * @author Petr Pchelko
+ * @since 1.9
+ */
+public interface DesktopDatatransferService {
+
+    /**
+     * If desktop is present - invokes a {@code Runnable} on
+     * the event dispatch thread. Otherwise invokes a {@code run()}
+     * method directly.
+     *
+     * @param r a {@code Runnable} to invoke
+     */
+    void invokeOnEventThread(Runnable r);
+
+    /**
+     * Get a platform-dependent default unicode encoding to use in
+     * datatransfer system.
+     *
+     * @return default unicode encoding
+     */
+    String getDefaultUnicodeEncoding();
+
+    /**
+     * Takes an appropriate {@code FlavorMap} from the desktop.
+     * If no appropriate table is found - uses a provided supplier to
+     * instantiate a table. If the desktop is absent - creates and returns
+     * a system singleton.
+     *
+     * @param supplier a constructor that should be used to create a new instance of
+     *                 the {@code FlavorMap}
+     * @return a {@code FlavorMap}
+     */
+    FlavorMap getFlavorMap(Supplier<FlavorMap> supplier);
+
+    /**
+     * Checks if desktop is present
+     *
+     * @return {@code true} is the desktop is present
+     */
+    boolean isDesktopPresent();
+
+    /**
+     * Returns platform-specific mappings for the specified native format.
+     * If there are no platform-specific mappings for this native, the method
+     * returns an empty {@code Set}
+     *
+     * @param nat a native format to return flavors for
+     * @return set of platform-specific mappings for a native format
+     */
+    LinkedHashSet<DataFlavor> getPlatformMappingsForNative(String nat);
+
+    /**
+     * Returns platform-specific mappings for the specified flavor.
+     * If there are no platform-specific mappings for this flavor, the method
+     * returns an empty {@code Set}
+     *
+     * @param df {@code DataFlavor} to return mappings for
+     * @return set of platform-specific mappings for a {@code DataFlavor}
+     */
+    LinkedHashSet<String> getPlatformMappingsForFlavor(DataFlavor df);
+
+    /**
+     * This method is called for text flavor mappings established while parsing
+     * the default flavor mappings file. It stores the "eoln" and "terminators"
+     * parameters which are not officially part of the MIME type. They are
+     * MIME parameters specific to the flavormap.properties file format.
+     */
+    void registerTextFlavorProperties(String nat, String charset,
+                                      String eoln, String terminators);
+}
--- a/jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java	Mon Jul 28 18:43:09 2014 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java	Mon Jul 28 19:02:56 2014 +0400
@@ -29,7 +29,6 @@
 
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
-import java.awt.datatransfer.UnsupportedFlavorException;
 
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
@@ -46,7 +45,6 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
-import java.util.List;
 
 import javax.imageio.ImageIO;
 import javax.imageio.ImageReader;
@@ -54,11 +52,11 @@
 import javax.imageio.ImageWriter;
 import javax.imageio.spi.ImageWriterSpi;
 
+import sun.datatransfer.DataFlavorUtil;
 import sun.awt.datatransfer.DataTransferer;
 import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
 
 import java.io.ByteArrayOutputStream;
-import java.util.stream.Stream;
 
 /**
  * Platform-specific support for the data transfer subsystem.
@@ -87,27 +85,30 @@
         return transferer;
     }
 
+    @Override
     public String getDefaultUnicodeEncoding() {
         return "iso-10646-ucs-2";
     }
 
+    @Override
     public boolean isLocaleDependentTextFormat(long format) {
         return false;
     }
 
+    @Override
     public boolean isTextFormat(long format) {
         return super.isTextFormat(format)
             || isMimeFormat(format, "text");
     }
 
+    @Override
     protected String getCharsetForTextFormat(Long lFormat) {
-        long format = lFormat.longValue();
-        if (isMimeFormat(format, "text")) {
-            String nat = getNativeForFormat(format);
+        if (isMimeFormat(lFormat, "text")) {
+            String nat = getNativeForFormat(lFormat);
             DataFlavor df = new DataFlavor(nat, null);
             // Ignore the charset parameter of the MIME type if the subtype
             // doesn't support charset.
-            if (!DataTransferer.doesSubtypeSupportCharset(df)) {
+            if (!DataFlavorUtil.doesSubtypeSupportCharset(df)) {
                 return null;
             }
             String charset = df.getParameter("charset");
@@ -118,6 +119,7 @@
         return super.getCharsetForTextFormat(lFormat);
     }
 
+    @Override
     protected boolean isURIListFormat(long format) {
         String nat = getNativeForFormat(format);
         if (nat == null) {
@@ -134,24 +136,27 @@
         return false;
     }
 
+    @Override
     public boolean isFileFormat(long format) {
         return format == FILE_NAME_ATOM.getAtom() ||
             format == DT_NET_FILE_ATOM.getAtom();
     }
 
+    @Override
     public boolean isImageFormat(long format) {
         return format == PNG_ATOM.getAtom() ||
             format == JFIF_ATOM.getAtom() ||
             isMimeFormat(format, "image");
     }
 
+    @Override
     protected Long getFormatForNativeAsLong(String str) {
         // Just get the atom. If it has already been retrived
         // once, we'll get a copy so this should be very fast.
-        long atom = XAtom.get(str).getAtom();
-        return Long.valueOf(atom);
+        return XAtom.get(str).getAtom();
     }
 
+    @Override
     protected String getNativeForFormat(long format) {
         return getTargetNameForAtom(format);
     }
@@ -167,6 +172,7 @@
         return XAtom.get(atom).getName();
     }
 
+    @Override
     protected byte[] imageToPlatformBytes(Image image, long format)
       throws IOException {
         String mimeType = null;
@@ -196,6 +202,7 @@
         }
     }
 
+    @Override
     protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList)
         throws IOException
     {
@@ -213,6 +220,7 @@
      * Translates either a byte array or an input stream which contain
      * platform-specific image data in the given format into an Image.
      */
+    @Override
     protected Image platformImageBytesToImage(
         byte[] bytes, long format) throws IOException
     {
@@ -317,8 +325,7 @@
             return flavors;
         }
 
-        DataFlavor df = null;
-
+        DataFlavor df;
         try {
             df = new DataFlavor(nat);
         } catch (Exception e) {
@@ -383,7 +390,7 @@
         String baseType = df.getPrimaryType() + "/" + df.getSubType();
         String mimeType = baseType;
 
-        if (charset != null && DataTransferer.isFlavorCharsetTextType(df)) {
+        if (charset != null && DataFlavorUtil.isFlavorCharsetTextType(df)) {
             mimeType += ";charset=" + charset;
         }
 
@@ -413,14 +420,14 @@
                     }
                 }
             }
-        } else if (DataTransferer.isFlavorCharsetTextType(df)) {
+        } else if (DataFlavorUtil.isFlavorCharsetTextType(df)) {
             // stringFlavor is semantically equivalent to the standard
             // "text/plain" MIME type.
             if (DataFlavor.stringFlavor.equals(df)) {
                 baseType = "text/plain";
             }
 
-            for (String encoding : DataTransferer.standardEncodings()) {
+            for (String encoding : DataFlavorUtil.standardEncodings()) {
                 if (!encoding.equals(charset)) {
                     natives.add(baseType + ";charset=" + encoding);
                 }
--- a/jdk/test/java/awt/datatransfer/SystemFlavorMap/AddFlavorTest.java	Mon Jul 28 18:43:09 2014 +0400
+++ b/jdk/test/java/awt/datatransfer/SystemFlavorMap/AddFlavorTest.java	Mon Jul 28 19:02:56 2014 +0400
@@ -23,11 +23,10 @@
  * questions.
  */
 
-import sun.awt.datatransfer.DataTransferer;
-
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.SystemFlavorMap;
 import java.util.*;
+import java.nio.charset.Charset;
 
 /*
  * @test
@@ -70,17 +69,8 @@
             // construct a unique String native
             key = key.concat("TEST");
 
-            for (DataFlavor element : flavorsSet)
+            for (DataFlavor element : flavorsSet) {
                 flavorMap.addFlavorForUnencodedNative(key, element);
-
-            // This part is valid only for X-based graphical systems
-            if (!System.getProperty("os.name").startsWith("Win") && !System.getProperty("os.name").startsWith("Mac") ) {
-                if (key.contains("/")) {
-                    Set<DataFlavor> fls = DataTransferer.getInstance().getPlatformMappingsForNative(key);
-                    flavorsSet.addAll(fls);
-                    if (!fls.isEmpty() && key.startsWith("text/"))
-                        flavorsSet.addAll(convertMimeTypeToDataFlavors(key));
-                }
             }
             hashVerify.put(key, new Vector(flavorsSet));
         }
@@ -103,12 +93,10 @@
     }
 
     void compareFlavors(List<DataFlavor> flavors1, List<DataFlavor> flavors2, String key){
-        DataTransferer.DataFlavorComparator comparator = new DataTransferer.DataFlavorComparator();
         for (DataFlavor flavor1 : flavors1) {
             boolean result = false;
             for (DataFlavor flavor2 : flavors2) {
-                if (comparator.compare(flavor1, flavor2) == 0)
-                    result = true;
+                if (flavor1.equals(flavor2)) result = true;
             }
             if (!result)
                 throw new RuntimeException("\n*** Error in verifyNewMappings()" +
@@ -125,7 +113,7 @@
     Set<DataFlavor> convertMimeTypeToDataFlavors(String baseType) throws Exception {
         Set<DataFlavor> result = new LinkedHashSet<>();
 
-        for (String charset : DataTransferer.standardEncodings()) {
+        for (String charset : getStandardEncodings()) {
             for (String txtClass : new String[]{"java.io.InputStream", "java.nio.ByteBuffer", "\"[B\""}) {
                 String mimeType = baseType + ";charset=" + charset + ";class=" + txtClass;
 
@@ -142,5 +130,17 @@
         }
         return result;
     }
+
+    Set<String> getStandardEncodings() {
+        Set<String> tempSet = new HashSet<>();
+        tempSet.add("US-ASCII");
+        tempSet.add("ISO-8859-1");
+        tempSet.add("UTF-8");
+        tempSet.add("UTF-16BE");
+        tempSet.add("UTF-16LE");
+        tempSet.add("UTF-16");
+        tempSet.add(Charset.defaultCharset().name());
+        return tempSet;
+    }
 }