4899516: Transferable has no DataFlavors when dragging from Gnome window to Swing
authordenis
Wed, 25 Nov 2009 21:27:06 +0300
changeset 4363 212067ed03e4
parent 4362 ad915ad8792f
child 4364 4b4427db3536
4899516: Transferable has no DataFlavors when dragging from Gnome window to Swing Reviewed-by: uta, dav Contributed-by: Damjan Jovanovic <damjan.jov@gmail.com>
jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java
jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java
jdk/src/solaris/lib/flavormap.properties
jdk/src/windows/classes/sun/awt/windows/WDataTransferer.java
jdk/test/java/awt/dnd/URIListBetweenJVMsTest/FileListTransferable.java
jdk/test/java/awt/dnd/URIListBetweenJVMsTest/InterprocessMessages.java
jdk/test/java/awt/dnd/URIListBetweenJVMsTest/SourceFileListFrame.java
jdk/test/java/awt/dnd/URIListBetweenJVMsTest/TargetFileListFrame.java
jdk/test/java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.html
jdk/test/java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java
jdk/test/java/awt/regtesthelpers/process/ProcessCommunicator.java
--- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Tue Nov 24 18:46:17 2009 +0300
+++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Wed Nov 25 21:27:06 2009 +0300
@@ -51,6 +51,9 @@
 import java.io.SequenceInputStream;
 import java.io.StringReader;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.Charset;
@@ -203,8 +206,6 @@
     private static final Map nativeEOLNs =
         Collections.synchronizedMap(new HashMap());
 
-    private static final byte [] UNICODE_NULL_TERMINATOR =  new byte [] {0,0};
-
     /**
      * The number of terminating NUL bytes for the Set of textNatives.
      */
@@ -628,6 +629,14 @@
     public abstract boolean isImageFormat(long format);
 
     /**
+     * Determines whether the format is a URI list we can convert to
+     * a DataFlavor.javaFileListFlavor.
+     */
+    protected boolean isURIListFormat(long format) {
+        return false;
+    }
+
+    /**
      * Returns a Map whose keys are all of the possible formats into which the
      * Transferable's transfer data flavors can be translated. The value of
      * each key is the DataFlavor in which the Transferable's data should be
@@ -1299,58 +1308,55 @@
             if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
                 throw new IOException("data translation failed");
             }
+
             final List list = (List)obj;
 
-            final ArrayList <String> fileList = new ArrayList<String>();
-
             final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
 
-            int nFiles = 0;
-            for (int i = 0; i < list.size(); i++) {
-                Object o = list.get(i);
-                if (o instanceof File || o instanceof String) {
-                    nFiles++;
+            final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
+
+            bos = convertFileListToBytes(fileList);
+
+
+        // Target data is a URI list. Source data must be a
+        // java.util.List which contains java.io.File or String instances.
+        } else if (isURIListFormat(format)) {
+            if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
+                throw new IOException("data translation failed");
+            }
+            String nat = getNativeForFormat(format);
+            String targetCharset = null;
+            if (nat != null) {
+                try {
+                    targetCharset = new DataFlavor(nat).getParameter("charset");
+                } catch (ClassNotFoundException cnfe) {
+                    throw new IOException(cnfe);
                 }
             }
-
-            try {
-                AccessController.doPrivileged(new PrivilegedExceptionAction() {
-                    public Object run() throws IOException {
-                        for (Object fileObject : list)
-                        {
-                            File file = castToFile(fileObject);
-                            if (null == System.getSecurityManager() ||
-                                !(isFileInWebstartedCache(file) ||
-                                isForbiddenToRead(file, userProtectionDomain)))
-                            {
-                                fileList.add(file.getCanonicalPath());
-                            }
-                        }
-                        return null;
-                    }
-                });
-            } catch (PrivilegedActionException pae) {
-                throw new IOException(pae.getMessage());
+            if (targetCharset == null) {
+                targetCharset = "UTF-8";
             }
-
-            if(fileList.isEmpty()) {
-                //store empty unicode string (null terminator)
-                bos.write(UNICODE_NULL_TERMINATOR);
-            } else {
-                for (int i = 0; i < fileList.size(); i++) {
-                    byte[] bytes = fileList.get(i).getBytes(getDefaultUnicodeEncoding());
-                    //store unicode string with null terminator
-                    bos.write(bytes, 0, bytes.length);
-                    bos.write(UNICODE_NULL_TERMINATOR);
-                }
+            final List list = (List)obj;
+            final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
+            final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
+            final ArrayList<String> uriList = new ArrayList<String>(fileList.size());
+            for (String fileObject : fileList) {
+                final URI uri = new File(fileObject).toURI();
+                // Some implementations are fussy about the number of slashes (file:///path/to/file is best)
+                try {
+                    uriList.add(new URI(uri.getScheme(), "", uri.getPath(), uri.getFragment()).toString());
+                } catch (URISyntaxException uriSyntaxException) {
+                    throw new IOException(uriSyntaxException);
+                  }
+              }
+
+            byte[] eoln = "\r\n".getBytes(targetCharset);
+            for (int i = 0; i < uriList.size(); i++) {
+                byte[] bytes = uriList.get(i).getBytes(targetCharset);
+                bos.write(bytes, 0, bytes.length);
+                bos.write(eoln, 0, eoln.length);
             }
 
-            // According to MSDN the byte array have to be double NULL-terminated.
-            // The array contains Unicode characters, so each NULL-terminator is
-            // a pair of bytes
-
-            bos.write(UNICODE_NULL_TERMINATOR);
-
         // Source data is an InputStream. For arbitrary flavors, just grab the
         // bytes and dump them into a byte array. For text flavors, decode back
         // to a String and recur to reencode according to the requested format.
@@ -1398,6 +1404,8 @@
         return ret;
     }
 
+    protected abstract ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList) throws IOException;
+
     private String removeSuspectedData(DataFlavor flavor, final Transferable contents, final String str)
             throws IOException
     {
@@ -1465,6 +1473,33 @@
         return true;
     }
 
+    private ArrayList<String> castToFiles(final List files,
+                                          final ProtectionDomain userProtectionDomain) throws IOException
+    {
+        final ArrayList<String> fileList = new ArrayList<String>();
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws IOException {
+                    for (Object fileObject : files)
+                    {
+                        File file = castToFile(fileObject);
+                        if (file != null &&
+                            (null == System.getSecurityManager() ||
+                            !(isFileInWebstartedCache(file) ||
+                            isForbiddenToRead(file, userProtectionDomain))))
+                        {
+                            fileList.add(file.getCanonicalPath());
+                        }
+                    }
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException pae) {
+            throw new IOException(pae.getMessage());
+        }
+        return fileList;
+    }
+
     // It is important do not use user's successors
     // of File class.
     private File castToFile(Object fileObject) throws IOException {
@@ -1473,6 +1508,8 @@
             filePath = ((File)fileObject).getCanonicalPath();
         } else if (fileObject instanceof String) {
            filePath = (String) fileObject;
+        } else {
+           return null;
         }
         return new File(filePath);
     }
@@ -1578,6 +1615,29 @@
             // Turn the list of Files into a List and return
             return Arrays.asList(files);
 
+        // Source data is a URI list. Convert to DataFlavor.javaFileListFlavor
+        // where possible.
+        } else if (isURIListFormat(format) && DataFlavor.javaFileListFlavor.equals(flavor)) {
+            try {
+                URI uris[] = dragQueryURIs(str, bytes, format, localeTransferable);
+                if (uris == null) {
+                    return null;
+                }
+                ArrayList files = new ArrayList();
+                for (URI uri : uris) {
+                    try {
+                        files.add(new File(uri));
+                    } catch (IllegalArgumentException illegalArg) {
+                        // When converting from URIs to less generic files,
+                        // common practice (Wine, SWT) seems to be to
+                        // silently drop the URIs that aren't local files.
+                    }
+                }
+                return files;
+            } finally {
+                str.close();
+            }
+
         // Target data is a String. Strip terminating NUL bytes. Decode bytes
         // into characters. Search-and-replace EOLN.
         } else if (String.class.equals(flavor.getRepresentationClass()) &&
@@ -1963,6 +2023,19 @@
     protected abstract String[] dragQueryFile(byte[] bytes);
 
     /**
+     * Decodes URIs from either a byte array or a stream.
+     */
+    protected URI[] dragQueryURIs(InputStream stream,
+                                  byte[] bytes,
+                                  long format,
+                                  Transferable localeTransferable)
+      throws IOException
+    {
+        throw new IOException(
+            new UnsupportedOperationException("not implemented on this platform"));
+    }
+
+    /**
      * Translates either a byte array or an input stream which contain
      * platform-specific image data in the given format into an Image.
      */
--- a/jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java	Tue Nov 24 18:46:17 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java	Wed Nov 25 21:27:06 2009 +0300
@@ -28,14 +28,21 @@
 import java.awt.Image;
 
 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;
 import java.awt.image.WritableRaster;
 
+import java.io.BufferedReader;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.IOException;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -48,6 +55,8 @@
 import sun.awt.datatransfer.DataTransferer;
 import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
 
+import java.io.ByteArrayOutputStream;
+
 /**
  * Platform-specific support for the data transfer subsystem.
  */
@@ -108,6 +117,22 @@
         return super.getCharsetForTextFormat(lFormat);
     }
 
+    protected boolean isURIListFormat(long format) {
+        String nat = getNativeForFormat(format);
+        if (nat == null) {
+            return false;
+        }
+        try {
+            DataFlavor df = new DataFlavor(nat);
+            if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) {
+                return true;
+            }
+        } catch (Exception e) {
+            // Not a MIME format.
+        }
+        return false;
+    }
+
     public boolean isFileFormat(long format) {
         return format == FILE_NAME_ATOM.getAtom() ||
             format == DT_NET_FILE_ATOM.getAtom();
@@ -170,6 +195,19 @@
         }
     }
 
+    protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList)
+        throws IOException
+    {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        for (int i = 0; i < fileList.size(); i++)
+        {
+               byte[] bytes = fileList.get(i).getBytes();
+               if (i != 0) bos.write(0);
+               bos.write(bytes, 0, bytes.length);
+        }
+        return bos;
+    }
+
     /**
      * Translates either a byte array or an input stream which contain
      * platform-specific image data in the given format into an Image.
@@ -215,6 +253,52 @@
         }
     }
 
+    protected URI[] dragQueryURIs(InputStream stream,
+                                  byte[] bytes,
+                                  long format,
+                                  Transferable localeTransferable)
+      throws IOException {
+
+        String charset = null;
+        if (localeTransferable != null &&
+            isLocaleDependentTextFormat(format) &&
+            localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor)) {
+            try {
+                charset = new String(
+                    (byte[])localeTransferable.getTransferData(javaTextEncodingFlavor),
+                    "UTF-8"
+                );
+            } catch (UnsupportedFlavorException cannotHappen) {
+            }
+        } else {
+            charset = getCharsetForTextFormat(format);
+        }
+        if (charset == null) {
+            // Only happens when we have a custom text type.
+            charset = getDefaultTextCharset();
+        }
+
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new InputStreamReader(stream, charset));
+            String line;
+            ArrayList<URI> uriList = new ArrayList<URI>();
+            URI uri;
+            while ((line = reader.readLine()) != null) {
+                try {
+                    uri = new URI(line);
+                } catch (URISyntaxException uriSyntaxException) {
+                    throw new IOException(uriSyntaxException);
+                }
+                uriList.add(uri);
+            }
+            return uriList.toArray(new URI[uriList.size()]);
+        } finally {
+            if (reader != null)
+                reader.close();
+        }
+    }
+
     /**
      * Returns true if and only if the name of the specified format Atom
      * constitutes a valid MIME type with the specified primary type.
--- a/jdk/src/solaris/lib/flavormap.properties	Tue Nov 24 18:46:17 2009 +0300
+++ b/jdk/src/solaris/lib/flavormap.properties	Wed Nov 25 21:27:06 2009 +0300
@@ -73,5 +73,6 @@
 TEXT=text/plain;eoln="\n";terminators=0
 STRING=text/plain;charset=iso8859-1;eoln="\n";terminators=0
 FILE_NAME=application/x-java-file-list;class=java.util.List
+text/uri-list=application/x-java-file-list;class=java.util.List
 PNG=image/x-java-image;class=java.awt.Image
 JFIF=image/x-java-image;class=java.awt.Image
--- a/jdk/src/windows/classes/sun/awt/windows/WDataTransferer.java	Tue Nov 24 18:46:17 2009 +0300
+++ b/jdk/src/windows/classes/sun/awt/windows/WDataTransferer.java	Wed Nov 25 21:27:06 2009 +0300
@@ -72,6 +72,10 @@
 import sun.awt.image.ImageRepresentation;
 import sun.awt.image.ToolkitImage;
 
+import java.util.ArrayList;
+
+import java.io.ByteArrayOutputStream;
+
 /**
  * Platform-specific support for the data transfer subsystem.
  *
@@ -342,6 +346,33 @@
         return imageDataToPlatformImageBytes(imageData, width, height, format);
     }
 
+    private static final byte [] UNICODE_NULL_TERMINATOR =  new byte [] {0,0};
+
+    protected ByteArrayOutputStream convertFileListToBytes(ArrayList<String> fileList)
+        throws IOException
+    {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+        if(fileList.isEmpty()) {
+            //store empty unicode string (null terminator)
+            bos.write(UNICODE_NULL_TERMINATOR);
+        } else {
+            for (int i = 0; i < fileList.size(); i++) {
+                byte[] bytes = fileList.get(i).getBytes(getDefaultUnicodeEncoding());
+                //store unicode string with null terminator
+                bos.write(bytes, 0, bytes.length);
+                bos.write(UNICODE_NULL_TERMINATOR);
+            }
+        }
+
+        // According to MSDN the byte array have to be double NULL-terminated.
+        // The array contains Unicode characters, so each NULL-terminator is
+        // a pair of bytes
+
+        bos.write(UNICODE_NULL_TERMINATOR);
+        return bos;
+    }
+
    /**
     * Returns a byte array which contains data special for the given format
     * and for the given image data.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListBetweenJVMsTest/FileListTransferable.java	Wed Nov 25 21:27:06 2009 +0300
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.File;
+import java.io.IOException;
+
+class FileListTransferable implements Transferable {
+
+    final private DataFlavor[] supportedFlavors =
+            {DataFlavor.javaFileListFlavor};
+
+    private java.util.List<File> list;
+
+    public FileListTransferable(java.util.List<File> list) {
+        this.list = list;
+    }
+
+    public DataFlavor[] getTransferDataFlavors() {
+        return supportedFlavors;
+    }
+
+    public boolean isDataFlavorSupported(DataFlavor flavor) {
+        for (DataFlavor df:supportedFlavors) {
+            if (df.equals(flavor)) return true;
+        }
+        return false;
+    }
+
+    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+        if (flavor.equals(DataFlavor.javaFileListFlavor)) {
+            return list;
+        }
+        throw new UnsupportedFlavorException(flavor);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListBetweenJVMsTest/InterprocessMessages.java	Wed Nov 25 21:27:06 2009 +0300
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+public interface InterprocessMessages {
+    final static int EXECUTION_IS_SUCCESSFULL = 0;
+    final static int WRONG_FILES_NUMBER_ON_TARGET = 212;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListBetweenJVMsTest/SourceFileListFrame.java	Wed Nov 25 21:27:06 2009 +0300
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import test.java.awt.regtesthelpers.Util;
+
+import java.awt.*;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureEvent;
+import java.io.File;
+import java.util.Arrays;
+
+
+class SourceFileListFrame extends Frame implements DragGestureListener {
+
+    private final static int SOURCE_POINT_SHIFT = 3;
+
+    private List list = new List(URIListBetweenJVMsTest.VISIBLE_RAWS_IN_LIST);
+    private File[] files;
+
+    SourceFileListFrame() {
+        super("Source File List Frame");
+        extractFilesFromTheWorkingDirectory();
+        initList();
+        initGUI();
+        new DragSource().createDefaultDragGestureRecognizer(list,
+                DnDConstants.ACTION_COPY,this);
+    }
+
+    private void extractFilesFromTheWorkingDirectory() {
+        files = new File(System.getProperty("java.home", "")).listFiles();
+    }
+
+    private void initList() {
+        for (File currFile:files) {
+            list.add(currFile.getName());
+        }
+    }
+
+    private void initGUI() {
+        this.addWindowListener(Util.getClosingWindowAdapter());
+        this.setLocation(300,250);
+        this.add(new Panel().add(list));
+        this.pack();
+        this.setVisible(true);
+    }
+
+    int getNextLocationX() {
+        return getX()+getWidth();
+    }
+
+    int getNextLocationY() {
+        return getY();
+    }
+
+    int getDragSourcePointX() {
+        return (int)list.getLocationOnScreen().getX()+(list.getWidth()/2);
+    }
+
+   int getDragSourcePointY() {
+        return (int)list.getLocationOnScreen().getY()+ SOURCE_POINT_SHIFT;
+    }
+
+    int getSourceFilesNumber() {
+        return files.length;
+    }
+
+    public void dragGestureRecognized(DragGestureEvent dge) {
+        String [] filesAsStringArray = list.getItems();
+        File [] files = new File[filesAsStringArray.length];
+        for (int fileNumber=0; fileNumber<filesAsStringArray.length ; fileNumber++ ) {
+            files[fileNumber]=new File(filesAsStringArray[fileNumber]);
+        }
+        dge.startDrag(null, new FileListTransferable(Arrays.asList(files)));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListBetweenJVMsTest/TargetFileListFrame.java	Wed Nov 25 21:27:06 2009 +0300
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import test.java.awt.regtesthelpers.Util;
+
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.dnd.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+
+class TargetFileListFrame extends Frame implements DropTargetListener {
+
+    private List list = new List(URIListBetweenJVMsTest.VISIBLE_RAWS_IN_LIST);
+    private int expectationTransferredFilesNumber;
+    private DataFlavor dropFlavor;
+
+    TargetFileListFrame(Point location, int expectationTransferredFilesNumber) {
+        try {
+            dropFlavor = new DataFlavor("text/uri-list;class=java.io.Reader");
+        } catch (Exception ex) {
+        }
+        this.expectationTransferredFilesNumber = expectationTransferredFilesNumber;
+        initGUI(location);
+        setDropTarget(new DropTarget(list, DnDConstants.ACTION_COPY,
+                this));
+    }
+
+    private void initGUI(Point location) {
+        this.setLocation(location);
+        this.addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                TargetFileListFrame.this.dispose();
+            }
+        });
+        this.add(new Panel().add(list));
+        this.pack();
+        this.setVisible(true);
+    }
+
+    public void dragEnter(DropTargetDragEvent dtde) {
+        if (dtde.getCurrentDataFlavorsAsList().contains(dropFlavor)) {
+            dtde.acceptDrag(DnDConstants.ACTION_COPY);
+        }
+    }
+
+    public void dragOver(DropTargetDragEvent dtde) {
+        if (dtde.getCurrentDataFlavorsAsList().contains(dropFlavor)) {
+            dtde.acceptDrag(DnDConstants.ACTION_COPY);
+        }
+    }
+
+    public void dropActionChanged(DropTargetDragEvent dtde) {
+        if (dtde.getCurrentDataFlavorsAsList().contains(dropFlavor)) {
+            dtde.acceptDrag(DnDConstants.ACTION_COPY);
+        }
+    }
+
+    public void dragExit(DropTargetEvent dte) {}
+
+    public void drop(DropTargetDropEvent dtde) {
+        list.removeAll();
+        dtde.acceptDrop(DnDConstants.ACTION_COPY);
+        java.util.List<File> fileList = extractListOfFiles(dtde);
+        for (File file:fileList) {
+            list.add(file.getName());
+        }
+
+        if (fileList.size() != expectationTransferredFilesNumber)
+        {
+            System.err.println("ERROR: Expected file number:"
+                    + expectationTransferredFilesNumber
+                    + "; Received file number: "
+                    + fileList.size());
+            TargetFileListFrame.this.dispose();
+            System.exit(InterprocessMessages.WRONG_FILES_NUMBER_ON_TARGET);
+        }
+
+        TargetFileListFrame.this.dispose();
+
+    }
+
+    private java.util.List<File> extractListOfFiles(DropTargetDropEvent dtde) {
+        BufferedReader reader = null;
+        ArrayList<File> files = new ArrayList<File>();
+        try {
+            reader = new BufferedReader((Reader)dtde.getTransferable().
+                    getTransferData(dropFlavor));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                files.add(new File(new URI(line)));
+            }
+        } catch (UnsupportedFlavorException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (URISyntaxException e) {
+            e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException ignored) {
+                }
+            }
+        }
+        return files;
+    }
+
+    Point getDropTargetPoint() {
+       return new Point((int)list.getLocationOnScreen().getX()+(list.getWidth()/2),
+                (int)list.getLocationOnScreen().getY()+(list.getHeight()/2));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.html	Wed Nov 25 21:27:06 2009 +0300
@@ -0,0 +1,25 @@
+<html>
+<!--  
+  @test
+  @bug 4899516
+  @summary Transferable has no DataFlavors when dragging from Gnome window to Swing
+  @author : area=dnd
+  @library ../../regtesthelpers
+  @library ../../regtesthelpers/process
+  @build Util
+  @build ProcessResults ProcessCommunicator 
+  @run applet/othervm URIListBetweenJVMsTest.html
+
+-->
+<head>
+<title> DnD of URI-List across JVM </title>
+</head>
+<body>
+
+<h1>URIListBetweenJVMsTest<br>Bug ID: 4899516</h1>
+
+<p> This is an AUTOMATIC test, simply wait for completion </p>
+
+<APPLET CODE="URIListBetweenJVMsTest.class" WIDTH=200 HEIGHT=200></APPLET>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java	Wed Nov 25 21:27:06 2009 +0300
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+  test
+  @bug 4899516
+  @summary Transferable has no DataFlavors when dragging from Gnome window to Swing
+  @author : area=dnd
+  @run applet URIListBetweenJVMsTest.html
+*/
+
+/**
+ * URIListBetweenJVMsTest.java
+ *
+ * summary: Transferable has no DataFlavors when dragging from Gnome window to Swing
+ */
+
+import static java.lang.Thread.sleep;
+
+import test.java.awt.regtesthelpers.process.ProcessCommunicator;
+import test.java.awt.regtesthelpers.process.ProcessResults;
+import test.java.awt.regtesthelpers.Util;
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.InputEvent;
+import java.io.*;
+
+public class URIListBetweenJVMsTest extends Applet {
+
+    // information related to the test in common
+    static int VISIBLE_RAWS_IN_LIST=15;
+
+    public void init() {
+        setLayout(new BorderLayout());
+
+    }//End  init()
+
+    public void start() {
+
+    String toolkit = Toolkit.getDefaultToolkit().getClass().getName();
+    if (toolkit.equals("sun.awt.windows.WToolkit")){
+        System.out.println("This test is not for the Windows platform. Passed.");
+        return;
+    } else {
+        System.out.println("Toolkit = " + toolkit);
+    }
+
+        SourceFileListFrame sourceFrame = new SourceFileListFrame();
+
+        Util.waitForIdle(null);
+
+        String [] args = new String [] {
+                String.valueOf(sourceFrame.getNextLocationX()),
+                String.valueOf(sourceFrame.getNextLocationY()),
+                String.valueOf(sourceFrame.getDragSourcePointX()),
+                String.valueOf(sourceFrame.getDragSourcePointY()),
+                String.valueOf(sourceFrame.getSourceFilesNumber())
+        };
+
+        String classpath = System.getProperty("java.class.path");
+        ProcessResults processResults =
+                ProcessCommunicator.executeChildProcess(this.getClass(), classpath, args);
+
+        verifyTestResults(processResults);
+
+    }// start()
+
+    private static void verifyTestResults(ProcessResults processResults) {
+        if ( InterprocessMessages.WRONG_FILES_NUMBER_ON_TARGET ==
+                processResults.getExitValue())
+        {
+            processResults.printProcessErrorOutput(System.err);
+            throw new RuntimeException("TEST IS FAILED: Target has recieved" +
+                    " wrong number of files.");
+        }
+        processResults.verifyStdErr(System.err);
+        processResults.verifyProcessExitValue(System.err);
+        processResults.printProcessStandartOutput(System.out);
+    }
+
+    //We cannot make an instance of the applet without the default constructor
+    public URIListBetweenJVMsTest () {
+        super();
+    }
+
+    //We need in this constructor to pass frame position between JVMs
+    public URIListBetweenJVMsTest (Point targetFrameLocation, Point dragSourcePoint,
+            int transferredFilesNumber)
+            throws InterruptedException
+    {
+        TargetFileListFrame targetFrame = new TargetFileListFrame(targetFrameLocation,
+                transferredFilesNumber);
+
+        Util.waitForIdle(null);
+
+        final Robot robot = Util.createRobot();
+
+        robot.mouseMove((int)dragSourcePoint.getX(),(int)dragSourcePoint.getY());
+        sleep(100);
+        robot.mousePress(InputEvent.BUTTON1_MASK);
+        sleep(100);
+        robot.mouseRelease(InputEvent.BUTTON1_MASK);
+        sleep(100);
+
+        Util.drag(robot, dragSourcePoint, targetFrame.getDropTargetPoint(),
+                InputEvent.BUTTON1_MASK);
+
+    }
+
+    enum InterprocessArguments {
+        TARGET_FRAME_X_POSITION_ARGUMENT,
+        TARGET_FRAME_Y_POSITION_ARGUMENT,
+        DRAG_SOURCE_POINT_X_ARGUMENT,
+        DRAG_SOURCE_POINT_Y_ARGUMENT,
+        FILES_IN_THE_LIST_NUMBER_ARGUMENT;
+
+        int extract (String [] args) {
+            return Integer.parseInt(args[this.ordinal()]);
+        }
+    }
+
+    public static void main (String [] args) {
+        Point dragSourcePoint = new Point(InterprocessArguments.DRAG_SOURCE_POINT_X_ARGUMENT.extract(args),
+                InterprocessArguments.DRAG_SOURCE_POINT_Y_ARGUMENT.extract(args));
+        Point targetFrameLocation = new Point(InterprocessArguments.TARGET_FRAME_X_POSITION_ARGUMENT.extract(args),
+                InterprocessArguments.TARGET_FRAME_Y_POSITION_ARGUMENT.extract(args));
+        int transferredFilesNumber = InterprocessArguments.FILES_IN_THE_LIST_NUMBER_ARGUMENT.extract(args);
+
+        try {
+            new URIListBetweenJVMsTest(targetFrameLocation, dragSourcePoint, transferredFilesNumber);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+
+}// class URIListBetweenJVMsTest
--- a/jdk/test/java/awt/regtesthelpers/process/ProcessCommunicator.java	Tue Nov 24 18:46:17 2009 +0300
+++ b/jdk/test/java/awt/regtesthelpers/process/ProcessCommunicator.java	Wed Nov 25 21:27:06 2009 +0300
@@ -146,7 +146,15 @@
                          final String classPathArguments, final String [] args)
     {
         StringBuilder commandBuilder = new StringBuilder();
-        commandBuilder.append(javaPath).append(classPathArguments).append(classToExecute.getName());
+        commandBuilder.append(javaPath).append(" ");
+        commandBuilder.append("-cp ").append(System.getProperty("test.classes", ".")).append(File.pathSeparatorChar);
+
+        if (classPathArguments.trim().length() > 0) {
+            commandBuilder.append(classPathArguments).append(" ");
+        }
+
+        commandBuilder.append(" ");
+        commandBuilder.append(classToExecute.getName());
         for (String argument:args) {
             commandBuilder.append(" ").append(argument);
         }