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