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   @bug 4870762
  27   @summary tests that a drop target JVM doesn't crash if the source doesn't export
  28            data in native formats.
  29   @author das@sparc.spb.su area=dnd
  30   @compile NoFormatsCrashTest.java
  31   @run applet NoFormatsCrashTest.html
  32 */
  33 
  34 // Note there is no @ in front of test above.  This is so that the
  35 //  harness will not mistake this file as a test file.  It should
  36 //  only see the html file as a test file. (the harness runs all
  37 //  valid test files, so it would run this test twice if this file
  38 //  were valid as well as the html file.)
  39 // Also, note the area= after Your Name in the author tag.  Here, you
  40 //  should put which functional area the test falls in.  See the
  41 //  AWT-core home page -> test areas and/or -> AWT team  for a list of
  42 //  areas.
  43 // Note also the 'NoFormatsCrashTest.html' in the run tag.  This should
  44 //  be changed to the name of the test.
  45 
  46 
  47 /**
  48  * NoFormatsCrashTest.java
  49  *
  50  * summary: tests that a drop target JVM doesn't crash if the source doesn't export
  51  *          data in native formats.
  52  */
  53 
  54 import java.applet.Applet;
  55 import java.awt.*;
  56 import java.awt.datatransfer.*;
  57 import java.awt.dnd.*;
  58 import java.awt.event.*;
  59 import java.io.*;
  60 
  61 
  62 //Automated tests should run as applet tests if possible because they
  63 // get their environments cleaned up, including AWT threads, any
  64 // test created threads, and any system resources used by the test
  65 // such as file descriptors.  (This is normally not a problem as
  66 // main tests usually run in a separate VM, however on some platforms
  67 // such as the Mac, separate VMs are not possible and non-applet
  68 // tests will cause problems).  Also, you don't have to worry about
  69 // synchronisation stuff in Applet tests they way you do in main
  70 // tests...
  71 
  72 
  73 public class NoFormatsCrashTest extends Applet {
  74 
  75     final Frame frame = new Frame();
  76     private volatile Process process;
  77 
  78     static final int FRAME_ACTIVATION_TIMEOUT = 2000;
  79 
  80     public static void main(String[] args) {
  81         NoFormatsCrashTest test = new NoFormatsCrashTest();
  82         test.run(args);
  83     }
  84 
  85     public void run(String[] args) {
  86         try {
  87             if (args.length != 4) {
  88                 throw new RuntimeException("Incorrect command line arguments.");
  89             }
  90 
  91             int x = Integer.parseInt(args[0]);
  92             int y = Integer.parseInt(args[1]);
  93             int w = Integer.parseInt(args[2]);
  94             int h = Integer.parseInt(args[3]);
  95 
  96             Panel panel = new DragSourcePanel();
  97 
  98             frame.setTitle("Drag source frame");
  99             frame.setLocation(500, 200);
 100             frame.add(panel);
 101             frame.pack();
 102             frame.setVisible(true);
 103 
 104             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
 105 
 106             Point sourcePoint = panel.getLocationOnScreen();
 107             Dimension d = panel.getSize();
 108             sourcePoint.translate(d.width / 2, d.height / 2);
 109 
 110             Point targetPoint = new Point(x + w / 2, y + h / 2);
 111 
 112             Robot robot = new Robot();
 113             robot.mouseMove(sourcePoint.x, sourcePoint.y);
 114             robot.keyPress(KeyEvent.VK_CONTROL);
 115             robot.mousePress(InputEvent.BUTTON1_MASK);
 116             for (; !sourcePoint.equals(targetPoint);
 117                  sourcePoint.translate(sign(targetPoint.x - sourcePoint.x),
 118                                        sign(targetPoint.y - sourcePoint.y))) {
 119                 robot.mouseMove(sourcePoint.x, sourcePoint.y);
 120                 Thread.sleep(50);
 121             }
 122             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 123             robot.keyRelease(KeyEvent.VK_CONTROL);
 124 
 125             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
 126 
 127             if (process.isAlive()) {
 128                 process.destroy();
 129             }
 130         } catch (Throwable e) {
 131             e.printStackTrace();
 132             throw new RuntimeException(e);
 133         }
 134     } // run()
 135 
 136     public void init() {
 137         frame.setTitle("Drop target frame");
 138         frame.setLocation(200, 200);
 139 
 140     } // init()
 141 
 142     public void start() {
 143         DropTargetPanel panel = new DropTargetPanel();
 144         frame.add(panel);
 145         frame.pack();
 146         frame.setVisible(true);
 147 
 148         try {
 149             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
 150 
 151             Point p = frame.getLocationOnScreen();
 152             Dimension d = frame.getSize();
 153 
 154             String javaPath = System.getProperty("java.home", "");
 155             String command = javaPath + File.separator + "bin" +
 156                 File.separator + "java -cp " + System.getProperty("test.classes", ".") +
 157                 " NoFormatsCrashTest " +
 158                 p.x + " " + p.y + " " + d.width + " " + d.height;
 159 
 160             process = Runtime.getRuntime().exec(command);
 161             ProcessResults pres = ProcessResults.doWaitFor(process);
 162             System.err.println("Child VM return code: " + pres.exitValue);
 163 
 164             if (pres.stderr != null && pres.stderr.length() > 0) {
 165                 System.err.println("========= Child VM System.err ========");
 166                 System.err.print(pres.stderr);
 167                 System.err.println("======================================");
 168             }
 169 
 170             if (pres.stdout != null && pres.stdout.length() > 0) {
 171                 System.err.println("========= Child VM System.out ========");
 172                 System.err.print(pres.stdout);
 173                 System.err.println("======================================");
 174             }
 175 
 176         } catch (Throwable e) {
 177             e.printStackTrace();
 178             throw new RuntimeException(e);
 179         }
 180 
 181         if (panel.isTestFailed()) {
 182             throw new RuntimeException();
 183         }
 184     } // start()
 185 
 186     public static int sign(int n) {
 187         return n < 0 ? -1 : n > 0 ? 1 : 0;
 188     }
 189 } // class NoFormatsCrashTest
 190 
 191 class TestTransferable implements Transferable {
 192 
 193     public static DataFlavor dataFlavor = null;
 194     static final Object data = new Object();
 195 
 196     static {
 197         DataFlavor df = null;
 198         try {
 199             df = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
 200                                 "; class=java.lang.Object");
 201         } catch (ClassNotFoundException e) {
 202             throw new ExceptionInInitializerError(e);
 203         }
 204         dataFlavor = df;
 205     }
 206 
 207     public DataFlavor[] getTransferDataFlavors() {
 208         return new DataFlavor[] { dataFlavor };
 209     }
 210 
 211     public boolean isDataFlavorSupported(DataFlavor df) {
 212         return dataFlavor.equals(df);
 213     }
 214 
 215     public Object getTransferData(DataFlavor df)
 216       throws UnsupportedFlavorException, IOException {
 217         if (!isDataFlavorSupported(df)) {
 218             throw new UnsupportedFlavorException(df);
 219         }
 220         return data;
 221     }
 222 }
 223 
 224 class DragSourcePanel extends Panel {
 225     public DragSourcePanel() {
 226         final Transferable t = new TestTransferable();
 227         final DragSourceListener dsl = new DragSourceAdapter() {
 228                 public void dragDropEnd(DragSourceDropEvent dtde) {
 229                     try {
 230                         Thread.sleep(100);
 231                     } catch (InterruptedException e) {
 232                         e.printStackTrace();
 233                     }
 234                     // This finishes child VM
 235                     System.exit(0);
 236                 }
 237             };
 238         final DragGestureListener dgl = new DragGestureListener() {
 239                 public void dragGestureRecognized(DragGestureEvent dge) {
 240                     dge.startDrag(null, t, dsl);
 241                 }
 242             };
 243         final DragSource ds = DragSource.getDefaultDragSource();
 244         final DragGestureRecognizer dgr =
 245             ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY,
 246                                                   dgl);
 247     }
 248 
 249     public Dimension getPreferredSize() {
 250         return new Dimension(100, 100);
 251     }
 252 }
 253 
 254 class DropTargetPanel extends Panel {
 255     private boolean testFailed = false;
 256     public DropTargetPanel() {
 257         final DropTargetListener dtl = new DropTargetAdapter() {
 258                 public void dragOver(DropTargetDragEvent dtde) {
 259                     try {
 260                         dtde.getCurrentDataFlavorsAsList();
 261                     } catch (Exception e) {
 262                         testFailed = true;
 263                         e.printStackTrace();
 264                     }
 265                 }
 266                 public void drop(DropTargetDropEvent dtde) {
 267                     dtde.rejectDrop();
 268                 }
 269             };
 270         final DropTarget dt = new DropTarget(this, dtl);
 271     }
 272 
 273     public boolean isTestFailed() {
 274         return testFailed;
 275     }
 276 
 277     public Dimension getPreferredSize() {
 278         return new Dimension(100, 100);
 279     }
 280 }
 281 
 282 class ProcessResults {
 283     public int exitValue;
 284     public String stdout;
 285     public String stderr;
 286 
 287     public ProcessResults() {
 288         exitValue = -1;
 289         stdout = "";
 290         stderr = "";
 291     }
 292 
 293     /**
 294      * Method to perform a "wait" for a process and return its exit value.
 295      * This is a workaround for <code>Process.waitFor()</code> never returning.
 296      */
 297     public static ProcessResults doWaitFor(Process p) {
 298         ProcessResults pres = new ProcessResults();
 299 
 300         InputStream in = null;
 301         InputStream err = null;
 302 
 303         try {
 304             in = p.getInputStream();
 305             err = p.getErrorStream();
 306 
 307             boolean finished = false;
 308 
 309             while (!finished) {
 310                 try {
 311                     while (in.available() > 0) {
 312                         pres.stdout += (char)in.read();
 313                     }
 314                     while (err.available() > 0) {
 315                         pres.stderr += (char)err.read();
 316                     }
 317                     // Ask the process for its exitValue. If the process
 318                     // is not finished, an IllegalThreadStateException
 319                     // is thrown. If it is finished, we fall through and
 320                     // the variable finished is set to true.
 321                     pres.exitValue = p.exitValue();
 322                     finished  = true;
 323                 }
 324                 catch (IllegalThreadStateException e) {
 325                     // Process is not finished yet;
 326                     // Sleep a little to save on CPU cycles
 327                     Thread.currentThread().sleep(500);
 328                 }
 329             }
 330             if (in != null) in.close();
 331             if (err != null) err.close();
 332         }
 333         catch (Throwable e) {
 334             System.err.println("doWaitFor(): unexpected exception");
 335             e.printStackTrace();
 336             throw new RuntimeException(e);
 337         }
 338         return pres;
 339     }
 340 }