8029565: java.awt.dnd.InvalidDnDOperationException: data translation failed on file drop
authorpchelko
Mon, 16 Dec 2013 17:35:08 +0400
changeset 23238 57997d148fc0
parent 22040 cb0198e8d989
child 23239 b9f47a000ebd
8029565: java.awt.dnd.InvalidDnDOperationException: data translation failed on file drop Reviewed-by: anthony, serb
jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java
jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java
jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/InterprocessMessages.java
jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/SourceFileListFrame.java
jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/TargetFileListFrame.java
jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.html
jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java
jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListTransferable.java
--- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Fri Dec 13 09:36:06 2013 -0800
+++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java	Mon Dec 16 17:35:08 2013 +0400
@@ -1598,6 +1598,30 @@
             // Turn the list of Files into a List and return
             theObject = Arrays.asList(files);
 
+            // Source data is a URI list. Convert to DataFlavor.javaFileListFlavor
+            // where possible.
+        } else if (isURIListFormat(format)
+                    && DataFlavor.javaFileListFlavor.equals(flavor)) {
+
+            try (ByteArrayInputStream str = new ByteArrayInputStream(bytes))  {
+
+                URI uris[] = dragQueryURIs(str, format, localeTransferable);
+                if (uris == null) {
+                    return null;
+                }
+                List<File> files = new ArrayList<>();
+                for (URI uri : uris) {
+                    try {
+                        files.add(new File(uri));
+                    } catch (IllegalArgumentException illegalArg) {
+                        // When converting from URIs to less generic files,
+                        // common practice (Wine, SWT) seems to be to
+                        // silently drop the URIs that aren't local files.
+                    }
+                }
+                theObject = files;
+            }
+
             // Target data is a String. Strip terminating NUL bytes. Decode bytes
             // into characters. Search-and-replace EOLN.
         } else if (String.class.equals(flavor.getRepresentationClass()) &&
--- a/jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java	Fri Dec 13 09:36:06 2013 -0800
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java	Mon Dec 16 17:35:08 2013 +0400
@@ -242,6 +242,7 @@
         }
     }
 
+    @Override
     protected String[] dragQueryFile(byte[] bytes) {
         XToolkit.awtLock();
         try {
@@ -252,8 +253,8 @@
         }
     }
 
+    @Override
     protected URI[] dragQueryURIs(InputStream stream,
-                                  byte[] bytes,
                                   long format,
                                   Transferable localeTransferable)
       throws IOException {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/InterprocessMessages.java	Mon Dec 16 17:35:08 2013 +0400
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2007, 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.
+ *
+ * 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.
+ */
+
+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/URIListToFileListBetweenJVMsTest/SourceFileListFrame.java	Mon Dec 16 17:35:08 2013 +0400
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ */
+
+import test.java.awt.regtesthelpers.Util;
+
+import java.awt.*;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.io.File;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+
+class SourceFileListFrame extends Frame implements DragGestureListener {
+
+    private final static int SOURCE_POINT_SHIFT = 3;
+
+    private List list = new List(URIListToFileListBetweenJVMsTest.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) {
+        java.util.List<URI> uriList = Stream.of(list.getItems())
+                                                .map(File::new)
+                                                .map(File::toURI)
+                                                .collect(Collectors.toList());
+
+        dge.startDrag(null, new URIListTransferable(uriList));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/TargetFileListFrame.java	Mon Dec 16 17:35:08 2013 +0400
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ */
+
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.*;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.IOException;
+
+class TargetFileListFrame extends Frame implements DropTargetListener {
+
+    private List list = new List(URIListToFileListBetweenJVMsTest.VISIBLE_RAWS_IN_LIST);
+    private int expectationTransferredFilesNumber;
+
+    TargetFileListFrame(Point location, int expectationTransferredFilesNumber) {
+        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(DataFlavor.javaFileListFlavor)) {
+            dtde.acceptDrag(DnDConstants.ACTION_COPY);
+        }
+    }
+
+    public void dragOver(DropTargetDragEvent dtde) {
+        if (dtde.getCurrentDataFlavorsAsList().contains(DataFlavor.javaFileListFlavor)) {
+            dtde.acceptDrag(DnDConstants.ACTION_COPY);
+        }
+    }
+
+    public void dropActionChanged(DropTargetDragEvent dtde) {
+        if (dtde.getCurrentDataFlavorsAsList().contains(DataFlavor.javaFileListFlavor)) {
+            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) {
+        java.util.List<File> fileList = null;
+        try {
+            fileList = (java.util.List<File>)dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
+        } catch (UnsupportedFlavorException | IOException e) {
+            e.printStackTrace();
+        }
+        return fileList;
+    }
+
+    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/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.html	Mon Dec 16 17:35:08 2013 +0400
@@ -0,0 +1,48 @@
+<!--
+ Copyright (c) 2013, 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.
+
+ 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.
+-->
+
+<html>
+<!--  
+  @test
+  @bug 8029565
+  @summary Conversion of a URI list to File list fails
+  @author Petr Pchelko <petr.pchelko@oracle.com>
+  @library ../../regtesthelpers
+  @library ../../regtesthelpers/process
+  @build Util
+  @build ProcessResults ProcessCommunicator
+  @run applet/othervm URIListToFileListBetweenJVMsTest.html
+
+-->
+<head>
+<title> DnD of File-List across JVM </title>
+</head>
+<body>
+
+<h1>URIListToFileListBetweenJVMsTest<br>Bug ID: 5079469</h1>
+
+<p> This is an AUTOMATIC test, simply wait for completion </p>
+
+<APPLET CODE="URIListToFileListBetweenJVMsTest.class" WIDTH=200 HEIGHT=200></APPLET>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java	Mon Dec 16 17:35:08 2013 +0400
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ */
+
+/*
+  test
+  @bug 8029565
+  @summary Conversion of a URI list to File list fails
+  @author Petr Pchelko <petr.pchelko@oracle.com>
+  @library ../../regtesthelpers
+  @library ../../regtesthelpers/process
+  @build Util
+  @build ProcessResults ProcessCommunicator
+  @run applet/othervm URIListToFileListBetweenJVMsTest.html
+ */
+
+/**
+ * URIListToFileListBetweenJVMsTest.java
+ *
+ * summary: DnD of File-List across JVM adds two empty items to the list
+ */
+
+import test.java.awt.regtesthelpers.Util;
+import test.java.awt.regtesthelpers.process.ProcessCommunicator;
+import test.java.awt.regtesthelpers.process.ProcessResults;
+
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.InputEvent;
+
+import static java.lang.Thread.sleep;
+
+public class URIListToFileListBetweenJVMsTest extends Applet {
+
+    // information related to the test in common
+    static int VISIBLE_RAWS_IN_LIST=15;
+
+    public void init() {
+        setLayout(new BorderLayout());
+    }
+
+    public void start() {
+
+        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())
+        };
+
+        ProcessResults processResults = ProcessCommunicator.executeChildProcess(this.getClass(), args);
+
+        verifyTestResults(processResults);
+
+    }
+
+    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 URIListToFileListBetweenJVMsTest() {
+        super();
+    }
+
+    //We need in this constructor to pass frame position between JVMs
+    public URIListToFileListBetweenJVMsTest(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) throws Exception {
+        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);
+
+        new URIListToFileListBetweenJVMsTest(targetFrameLocation, dragSourcePoint, transferredFilesNumber);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListTransferable.java	Mon Dec 16 17:35:08 2013 +0400
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ */
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+class URIListTransferable implements Transferable {
+
+    private final DataFlavor supportedFlavor;
+
+    private List<URI> list;
+
+    public URIListTransferable(List<URI> list) {
+        try {
+            this.supportedFlavor = new DataFlavor("text/uri-list;class=java.lang.String");
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException("FAILED: could not create a DataFlavor");
+        }
+        this.list = list;
+    }
+
+    public DataFlavor[] getTransferDataFlavors() {
+        return new DataFlavor[] { supportedFlavor };
+    }
+
+    public boolean isDataFlavorSupported(DataFlavor flavor) {
+        return supportedFlavor.equals(flavor);
+    }
+
+    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+        if (supportedFlavor.equals(flavor)) {
+            return list.stream()
+                    .map(URI::toASCIIString)
+                    .collect(StringBuilder::new,
+                             (builder, uri)-> { builder.append(uri).append("\r\n"); },
+                             StringBuilder::append).toString();
+        }
+        throw new UnsupportedFlavorException(flavor);
+    }
+}