|
1 /* |
|
2 * Copyright (c) 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 8152974 |
|
27 * @key headful |
|
28 * @summary AWT hang occurrs when sequenced events arrive out of sequence |
|
29 * @run main SequencedEventTest |
|
30 */ |
|
31 import sun.awt.AppContext; |
|
32 import sun.awt.SunToolkit; |
|
33 |
|
34 import java.awt.Robot; |
|
35 import java.awt.Point; |
|
36 import java.awt.Dimension; |
|
37 import java.awt.FlowLayout; |
|
38 import java.awt.AWTEvent; |
|
39 import java.awt.Toolkit; |
|
40 import java.awt.event.ActionEvent; |
|
41 import java.awt.event.ActionListener; |
|
42 import java.awt.event.InputEvent; |
|
43 import java.lang.reflect.Constructor; |
|
44 import java.util.concurrent.CountDownLatch; |
|
45 |
|
46 import javax.swing.JFrame; |
|
47 import javax.swing.JButton; |
|
48 import javax.swing.SwingUtilities; |
|
49 import javax.swing.JTextArea; |
|
50 |
|
51 public class SequencedEventTest extends JFrame implements ActionListener { |
|
52 private JButton spamMeButton; |
|
53 private static Robot robot; |
|
54 private static SequencedEventTest window; |
|
55 private static AppContext context; |
|
56 |
|
57 public static void main(String[] args) throws Exception { |
|
58 SwingUtilities.invokeAndWait(() -> { |
|
59 window = new SequencedEventTest(); |
|
60 window.setVisible(true); |
|
61 }); |
|
62 |
|
63 robot = new Robot(); |
|
64 robot.waitForIdle(); |
|
65 |
|
66 Point pt = window.spamMeButton.getLocationOnScreen(); |
|
67 Dimension d = window.spamMeButton.getSize(); |
|
68 |
|
69 robot.mouseMove(pt.x + d.width / 2, pt.y + d.height / 2); |
|
70 robot.waitForIdle(); |
|
71 robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); |
|
72 robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); |
|
73 /* |
|
74 *Cannot have robot.waitForIdle() here since it will block the test forever, |
|
75 * in the case of failure and the test will timeout. |
|
76 */ |
|
77 |
|
78 try { |
|
79 /* |
|
80 * Wait for 2 seconds, and then see if all the sequenced events are dispatched. |
|
81 */ |
|
82 Thread.sleep(2000); |
|
83 AWTEvent ev = Toolkit.getDefaultToolkit().getSystemEventQueue(). |
|
84 peekEvent(java.awt.event.FocusEvent.FOCUS_LAST + 1); |
|
85 |
|
86 if (ev != null) |
|
87 throw new RuntimeException("Test case failed!"); |
|
88 } catch (InterruptedException e) { |
|
89 throw new RuntimeException("Test case failed." + e.getMessage()); |
|
90 } |
|
91 |
|
92 /* |
|
93 * In the case of failure, the cleanup job cannot be executed, since it |
|
94 * will block the test. |
|
95 */ |
|
96 System.out.println("Test case succeeded."); |
|
97 context.dispose(); |
|
98 SwingUtilities.invokeAndWait(() -> window.dispose()); |
|
99 } |
|
100 |
|
101 public SequencedEventTest() { |
|
102 super("Test Window"); |
|
103 |
|
104 setLayout(new FlowLayout()); |
|
105 JTextArea textBlock = new JTextArea("Lorem ipsum dolor sit amet..."); |
|
106 add(textBlock); |
|
107 |
|
108 spamMeButton = new JButton("Press me!"); |
|
109 spamMeButton.addActionListener(this); |
|
110 add(spamMeButton); |
|
111 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
|
112 pack(); |
|
113 } |
|
114 |
|
115 @Override |
|
116 public void actionPerformed(ActionEvent e) { |
|
117 if(e.getSource() == spamMeButton) { |
|
118 AWTEvent eventOne = getSequencedEvent(); |
|
119 AWTEvent eventFour = getSequencedEvent(); |
|
120 ThreadGroup tg = new ThreadGroup("TestThreadGroup" ); |
|
121 CountDownLatch latch = new CountDownLatch(1); |
|
122 Thread t = new Thread(tg, () -> { |
|
123 context = SunToolkit.createNewAppContext(); |
|
124 AWTEvent eventTwo = getSequencedEvent(); |
|
125 AWTEvent eventThree = getSequencedEvent(); |
|
126 |
|
127 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(eventThree); |
|
128 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(new ActionEvent(this, 0, null)); |
|
129 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(new ActionEvent(this, 1, null)); |
|
130 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(eventTwo); |
|
131 |
|
132 latch.countDown(); |
|
133 }); |
|
134 |
|
135 t.start(); |
|
136 try { |
|
137 latch.await(); |
|
138 }catch (InterruptedException ex) { |
|
139 throw new RuntimeException("Test case failed."); |
|
140 } |
|
141 |
|
142 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(eventFour); |
|
143 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(new ActionEvent(this, 2, null)); |
|
144 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(new ActionEvent(this, 3, null)); |
|
145 Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(eventOne); |
|
146 |
|
147 try { |
|
148 t.join(); |
|
149 } catch (InterruptedException ex) { |
|
150 throw new RuntimeException("Test case failed."); |
|
151 } |
|
152 } |
|
153 } |
|
154 |
|
155 private AWTEvent getSequencedEvent() |
|
156 { |
|
157 AWTEvent wrapMe = new AWTEvent(this, AWTEvent.RESERVED_ID_MAX) {}; |
|
158 |
|
159 try { |
|
160 /* |
|
161 * SequencedEvent is a package private class, which cannot be instantiated |
|
162 * by importing. So use reflection to create an instance. |
|
163 */ |
|
164 Class<? extends AWTEvent> seqClass = (Class<? extends AWTEvent>) Class.forName("java.awt.SequencedEvent"); |
|
165 Constructor<? extends AWTEvent> seqConst = seqClass.getConstructor(AWTEvent.class); |
|
166 seqConst.setAccessible(true);; |
|
167 return seqConst.newInstance(wrapMe); |
|
168 } catch (Throwable err) { |
|
169 throw new RuntimeException("Unable to instantiate SequencedEvent",err); |
|
170 } |
|
171 } |
|
172 } |