1 /* 2 * Copyright (c) 2015, 2017, 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 6980209 28 * @summary Make tracking SecondaryLoop.enter/exit methods easier 29 * @author Semyon Sadetsky 30 */ 31 32 import javax.swing.*; 33 import java.awt.*; 34 import java.awt.event.ActionEvent; 35 import java.awt.event.ActionListener; 36 import java.awt.event.KeyEvent; 37 import java.awt.event.KeyListener; 38 import java.util.logging.Logger; 39 40 public class bug6980209 implements ActionListener { 41 private final static Logger log = 42 Logger.getLogger("java.awt.event.WaitDispatchSupport"); 43 public static final int ATTEMPTS = 100; 44 public static final int EVENTS = 5; 45 46 private static boolean runInEDT; 47 private static JFrame frame; 48 private static int disorderCounter = 0; 49 private static Boolean enterReturn; 50 private static Boolean exitReturn; 51 private static int dispatchedEvents; 52 53 public static void main(String[] args) throws Exception { 54 System.out.println( 55 "PLEASE DO NOT TOUCH KEYBOARD AND MOUSE DURING THE TEST RUN!"); 56 // log.setLevel(java.util.logging.Level.FINE); 57 // log.setLevel(java.util.logging.Level.FINEST); 58 try { 59 SwingUtilities.invokeAndWait(new Runnable() { 60 public void run() { 61 frame = new JFrame(); 62 frame.setUndecorated(true); 63 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 64 setup(frame); 65 } 66 }); 67 testExitBeforeEnter(); 68 System.out.println("Run random test in EDT"); 69 runInEDT = true; 70 testRandomly(); 71 System.out.println("Run random test in another thread"); 72 runInEDT = false; 73 testRandomly(); 74 System.out.println("ok"); 75 76 } finally { 77 SwingUtilities.invokeAndWait(new Runnable() { 78 @Override 79 public void run() { 80 frame.dispose(); 81 } 82 }); 83 } 84 } 85 86 private static void testExitBeforeEnter() throws Exception { 87 final SecondaryLoop loop = 88 Toolkit.getDefaultToolkit().getSystemEventQueue() 89 .createSecondaryLoop(); 90 loop.exit(); 91 Robot robot = new Robot(); 92 robot.mouseWheel(1); 93 robot.waitForIdle(); 94 SwingUtilities.invokeAndWait(new Runnable() { 95 @Override 96 public void run() { 97 if(loop.enter()) { 98 throw new RuntimeException("Wrong enter() return value"); 99 } 100 } 101 }); 102 } 103 104 private static void testRandomly() throws AWTException { 105 disorderCounter = 0; 106 final Robot robot = new Robot(); 107 for (int i = 0; i < ATTEMPTS; i++) { 108 enterReturn = null; 109 exitReturn = null; 110 dispatchedEvents = 0; 111 synchronized (bug6980209.class) { 112 try { 113 for (int j = 0; j < EVENTS; j++) { 114 robot.keyPress(KeyEvent.VK_1); 115 robot.keyRelease(KeyEvent.VK_1); 116 } 117 118 // trigger the button action that starts secondary loop 119 robot.keyPress(KeyEvent.VK_SPACE); 120 robot.keyRelease(KeyEvent.VK_SPACE); 121 122 for (int j = 0; j < EVENTS; j++) { 123 robot.keyPress(KeyEvent.VK_1); 124 robot.keyRelease(KeyEvent.VK_1); 125 } 126 long time = System.nanoTime(); 127 // wait for enter() returns 128 bug6980209.class.wait(1000); 129 if (enterReturn == null) { 130 System.out.println("wait time=" + 131 ((System.nanoTime() - time) / 1E9) + 132 " seconds"); 133 throw new RuntimeException( 134 "It seems the secondary loop will never end"); 135 } 136 if (!enterReturn) disorderCounter++; 137 138 robot.waitForIdle(); 139 if (dispatchedEvents < 140 2 * EVENTS) { //check that all events are dispatched 141 throw new RuntimeException( 142 "KeyEvent.VK_1 has been lost!"); 143 } 144 145 } catch (InterruptedException e) { 146 throw new RuntimeException("Interrupted!"); 147 } 148 } 149 } 150 if (disorderCounter == 0) { 151 System.out.println( 152 "Zero disordered enter/exit caught. It is recommended to run scenario again"); 153 } else { 154 System.out.println( 155 "Disordered calls is " + disorderCounter + " from " + 156 ATTEMPTS); 157 } 158 } 159 160 private static void setup(final JFrame frame) { 161 JButton jButton = new JButton("Button"); 162 frame.getContentPane().add(jButton); 163 jButton.addActionListener(new bug6980209()); 164 frame.pack(); 165 frame.setVisible(true); 166 jButton.setFocusable(true); 167 jButton.requestFocus(); 168 jButton.addKeyListener(new KeyListener() { 169 @Override 170 public void keyTyped(KeyEvent e) { 171 } 172 173 @Override 174 public void keyPressed(KeyEvent e) { 175 if (e.getKeyChar() == '1') dispatchedEvents++; 176 } 177 178 @Override 179 public void keyReleased(KeyEvent e) { 180 if (e.getKeyChar() == '1') dispatchedEvents++; 181 } 182 }); 183 } 184 185 186 @Override 187 public void actionPerformed(ActionEvent e) { 188 if (runInEDT) { 189 runSecondaryLoop(); 190 return; 191 } 192 new Thread("Secondary loop run thread") { 193 @Override 194 public void run() { 195 runSecondaryLoop(); 196 } 197 }.start(); 198 } 199 200 private static void runSecondaryLoop() { 201 log.fine("\n---TEST START---"); 202 203 final SecondaryLoop loop = 204 Toolkit.getDefaultToolkit().getSystemEventQueue() 205 .createSecondaryLoop(); 206 207 final Object LOCK = new Object(); //lock to start simultaneously 208 Thread exitThread = new Thread("Exit thread") { 209 @Override 210 public void run() { 211 synchronized (LOCK) { 212 LOCK.notify(); 213 } 214 Thread.yield(); 215 exitReturn = loop.exit(); 216 log.fine("exit() returns " + exitReturn); 217 } 218 }; 219 220 synchronized (LOCK) { 221 try { 222 exitThread.start(); 223 LOCK.wait(); 224 } catch (InterruptedException e1) { 225 throw new RuntimeException("What?"); 226 } 227 } 228 229 enterReturn = loop.enter(); 230 log.fine("enter() returns " + enterReturn); 231 232 try { 233 exitThread.join(); 234 } catch (InterruptedException e) { 235 throw new RuntimeException("What?"); 236 } 237 synchronized (bug6980209.class) { 238 bug6980209.class.notifyAll(); 239 } 240 log.fine("\n---TEST END---"); 241 } 242 }