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