1 /*
   2  * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25   @test
  26   @key headful
  27   @bug 4870762
  28   @summary tests that a drop target JVM doesn't crash if the source doesn't export
  29            data in native formats.
  30   @run main NoFormatsCrashTest main
  31 */
  32 
  33 import java.awt.*;
  34 import java.awt.datatransfer.*;
  35 import java.awt.dnd.*;
  36 import java.awt.event.*;
  37 import java.io.*;
  38 
  39 public class NoFormatsCrashTest {
  40 
  41     final Frame frame = new Frame();
  42     private volatile Process process;
  43 
  44     static final int FRAME_ACTIVATION_TIMEOUT = 2000;
  45 
  46     public static void main(String[] args) {
  47         if (args.length > 0 && args[0].equals("main")) {
  48             NoFormatsCrashTest test = new NoFormatsCrashTest();
  49             test.init();
  50             test.start();
  51             return;
  52         }
  53 
  54         NoFormatsCrashTest test = new NoFormatsCrashTest();
  55         test.run(args);
  56     }
  57 
  58     public void run(String[] args) {
  59         try {
  60             if (args.length != 4) {
  61                 throw new RuntimeException("Incorrect command line arguments.");
  62             }
  63 
  64             int x = Integer.parseInt(args[0]);
  65             int y = Integer.parseInt(args[1]);
  66             int w = Integer.parseInt(args[2]);
  67             int h = Integer.parseInt(args[3]);
  68 
  69             Panel panel = new DragSourcePanel();
  70 
  71             frame.setTitle("Drag source frame");
  72             frame.setLocation(500, 200);
  73             frame.add(panel);
  74             frame.pack();
  75             frame.setVisible(true);
  76 
  77             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
  78 
  79             Point sourcePoint = panel.getLocationOnScreen();
  80             Dimension d = panel.getSize();
  81             sourcePoint.translate(d.width / 2, d.height / 2);
  82 
  83             Point targetPoint = new Point(x + w / 2, y + h / 2);
  84 
  85             Robot robot = new Robot();
  86             robot.mouseMove(sourcePoint.x, sourcePoint.y);
  87             robot.keyPress(KeyEvent.VK_CONTROL);
  88             robot.mousePress(InputEvent.BUTTON1_MASK);
  89             for (; !sourcePoint.equals(targetPoint);
  90                  sourcePoint.translate(sign(targetPoint.x - sourcePoint.x),
  91                                        sign(targetPoint.y - sourcePoint.y))) {
  92                 robot.mouseMove(sourcePoint.x, sourcePoint.y);
  93                 Thread.sleep(50);
  94             }
  95             robot.mouseRelease(InputEvent.BUTTON1_MASK);
  96             robot.keyRelease(KeyEvent.VK_CONTROL);
  97 
  98             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
  99 
 100             if (process.isAlive()) {
 101                 process.destroy();
 102             }
 103         } catch (Throwable e) {
 104             e.printStackTrace();
 105             throw new RuntimeException(e);
 106         }
 107     } // run()
 108 
 109     public void init() {
 110         frame.setTitle("Drop target frame");
 111         frame.setLocation(200, 200);
 112 
 113     } // init()
 114 
 115     public void start() {
 116         DropTargetPanel panel = new DropTargetPanel();
 117         frame.add(panel);
 118         frame.pack();
 119         frame.setVisible(true);
 120 
 121         try {
 122             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
 123 
 124             Point p = frame.getLocationOnScreen();
 125             Dimension d = frame.getSize();
 126 
 127             String javaPath = System.getProperty("java.home", "");
 128             String command = javaPath + File.separator + "bin" +
 129                 File.separator + "java -cp " + System.getProperty("test.classes", ".") +
 130                 " NoFormatsCrashTest " +
 131                 p.x + " " + p.y + " " + d.width + " " + d.height;
 132 
 133             process = Runtime.getRuntime().exec(command);
 134             ProcessResults pres = ProcessResults.doWaitFor(process);
 135             System.err.println("Child VM return code: " + pres.exitValue);
 136 
 137             if (pres.stderr != null && pres.stderr.length() > 0) {
 138                 System.err.println("========= Child VM System.err ========");
 139                 System.err.print(pres.stderr);
 140                 System.err.println("======================================");
 141             }
 142 
 143             if (pres.stdout != null && pres.stdout.length() > 0) {
 144                 System.err.println("========= Child VM System.out ========");
 145                 System.err.print(pres.stdout);
 146                 System.err.println("======================================");
 147             }
 148 
 149         } catch (Throwable e) {
 150             e.printStackTrace();
 151             throw new RuntimeException(e);
 152         }
 153 
 154         if (panel.isTestFailed()) {
 155             throw new RuntimeException();
 156         }
 157     } // start()
 158 
 159     public static int sign(int n) {
 160         return n < 0 ? -1 : n > 0 ? 1 : 0;
 161     }
 162 } // class NoFormatsCrashTest
 163 
 164 class TestTransferable implements Transferable {
 165 
 166     public static DataFlavor dataFlavor = null;
 167     static final Object data = new Object();
 168 
 169     static {
 170         DataFlavor df = null;
 171         try {
 172             df = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
 173                                 "; class=java.lang.Object");
 174         } catch (ClassNotFoundException e) {
 175             throw new ExceptionInInitializerError(e);
 176         }
 177         dataFlavor = df;
 178     }
 179 
 180     public DataFlavor[] getTransferDataFlavors() {
 181         return new DataFlavor[] { dataFlavor };
 182     }
 183 
 184     public boolean isDataFlavorSupported(DataFlavor df) {
 185         return dataFlavor.equals(df);
 186     }
 187 
 188     public Object getTransferData(DataFlavor df)
 189       throws UnsupportedFlavorException, IOException {
 190         if (!isDataFlavorSupported(df)) {
 191             throw new UnsupportedFlavorException(df);
 192         }
 193         return data;
 194     }
 195 }
 196 
 197 class DragSourcePanel extends Panel {
 198     public DragSourcePanel() {
 199         final Transferable t = new TestTransferable();
 200         final DragSourceListener dsl = new DragSourceAdapter() {
 201                 public void dragDropEnd(DragSourceDropEvent dtde) {
 202                     try {
 203                         Thread.sleep(100);
 204                     } catch (InterruptedException e) {
 205                         e.printStackTrace();
 206                     }
 207                     // This finishes child VM
 208                     System.exit(0);
 209                 }
 210             };
 211         final DragGestureListener dgl = new DragGestureListener() {
 212                 public void dragGestureRecognized(DragGestureEvent dge) {
 213                     dge.startDrag(null, t, dsl);
 214                 }
 215             };
 216         final DragSource ds = DragSource.getDefaultDragSource();
 217         final DragGestureRecognizer dgr =
 218             ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY,
 219                                                   dgl);
 220     }
 221 
 222     public Dimension getPreferredSize() {
 223         return new Dimension(100, 100);
 224     }
 225 }
 226 
 227 class DropTargetPanel extends Panel {
 228     private boolean testFailed = false;
 229     public DropTargetPanel() {
 230         final DropTargetListener dtl = new DropTargetAdapter() {
 231                 public void dragOver(DropTargetDragEvent dtde) {
 232                     try {
 233                         dtde.getCurrentDataFlavorsAsList();
 234                     } catch (Exception e) {
 235                         testFailed = true;
 236                         e.printStackTrace();
 237                     }
 238                 }
 239                 public void drop(DropTargetDropEvent dtde) {
 240                     dtde.rejectDrop();
 241                 }
 242             };
 243         final DropTarget dt = new DropTarget(this, dtl);
 244     }
 245 
 246     public boolean isTestFailed() {
 247         return testFailed;
 248     }
 249 
 250     public Dimension getPreferredSize() {
 251         return new Dimension(100, 100);
 252     }
 253 }
 254 
 255 class ProcessResults {
 256     public int exitValue;
 257     public String stdout;
 258     public String stderr;
 259 
 260     public ProcessResults() {
 261         exitValue = -1;
 262         stdout = "";
 263         stderr = "";
 264     }
 265 
 266     /**
 267      * Method to perform a "wait" for a process and return its exit value.
 268      * This is a workaround for <code>Process.waitFor()</code> never returning.
 269      */
 270     public static ProcessResults doWaitFor(Process p) {
 271         ProcessResults pres = new ProcessResults();
 272 
 273         InputStream in = null;
 274         InputStream err = null;
 275 
 276         try {
 277             in = p.getInputStream();
 278             err = p.getErrorStream();
 279 
 280             boolean finished = false;
 281 
 282             while (!finished) {
 283                 try {
 284                     while (in.available() > 0) {
 285                         pres.stdout += (char)in.read();
 286                     }
 287                     while (err.available() > 0) {
 288                         pres.stderr += (char)err.read();
 289                     }
 290                     // Ask the process for its exitValue. If the process
 291                     // is not finished, an IllegalThreadStateException
 292                     // is thrown. If it is finished, we fall through and
 293                     // the variable finished is set to true.
 294                     pres.exitValue = p.exitValue();
 295                     finished  = true;
 296                 }
 297                 catch (IllegalThreadStateException e) {
 298                     // Process is not finished yet;
 299                     // Sleep a little to save on CPU cycles
 300                     Thread.currentThread().sleep(500);
 301                 }
 302             }
 303             if (in != null) in.close();
 304             if (err != null) err.close();
 305         }
 306         catch (Throwable e) {
 307             System.err.println("doWaitFor(): unexpected exception");
 308             e.printStackTrace();
 309             throw new RuntimeException(e);
 310         }
 311         return pres;
 312     }
 313 }