# HG changeset patch # User pchelko # Date 1387200908 -14400 # Node ID 57997d148fc043185757be1f9ba01b6c64581a6c # Parent cb0198e8d989b38c1cacf8b25102e4f04b6b5085 8029565: java.awt.dnd.InvalidDnDOperationException: data translation failed on file drop Reviewed-by: anthony, serb diff -r cb0198e8d989 -r 57997d148fc0 jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.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 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()) && diff -r cb0198e8d989 -r 57997d148fc0 jdk/src/solaris/classes/sun/awt/X11/XDataTransferer.java --- 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 { diff -r cb0198e8d989 -r 57997d148fc0 jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/InterprocessMessages.java --- /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; +} diff -r cb0198e8d989 -r 57997d148fc0 jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/SourceFileListFrame.java --- /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 uriList = Stream.of(list.getItems()) + .map(File::new) + .map(File::toURI) + .collect(Collectors.toList()); + + dge.startDrag(null, new URIListTransferable(uriList)); + } +} diff -r cb0198e8d989 -r 57997d148fc0 jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/TargetFileListFrame.java --- /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 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 extractListOfFiles(DropTargetDropEvent dtde) { + java.util.List fileList = null; + try { + fileList = (java.util.List)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)); + } +} diff -r cb0198e8d989 -r 57997d148fc0 jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.html --- /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 @@ + + + + + + DnD of File-List across JVM + + + +

URIListToFileListBetweenJVMsTest
Bug ID: 5079469

+ +

This is an AUTOMATIC test, simply wait for completion

+ + + + diff -r cb0198e8d989 -r 57997d148fc0 jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java --- /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 + @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); + } +} diff -r cb0198e8d989 -r 57997d148fc0 jdk/test/java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListTransferable.java --- /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 list; + + public URIListTransferable(List 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); + } +}