blob: e9e314aaa8f6faef0466d252f27ebc1ac3e07345 [file] [log] [blame]
package org.jdesktop.swinghelper.debug;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
final class Tests {
public static void main(String[] args) {
if (args.length == 0) {
return;
}
String mode = args[0];
new EventDispatchThreadHangMonitor().initMonitoring();
if ("deadlock".equals(mode)) {
runDeadlockTest();
return;
}
EventQueue.invokeLater(
() -> {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
switch (mode) {
case "exception":
runExceptionTest(frame);
break;
case "focus":
runFocusTest(frame);
break;
case "modal-hang":
runModalTest(frame, true);
break;
case "modal-no-hang":
runModalTest(frame, false);
break;
default:
System.err.println("unknown regression test '" + mode + "'");
System.exit(1);
}
frame.pack();
frame.setVisible(true);
});
}
public static void runDeadlockTest() {
class Locker {
private Locker locker;
public void setLocker(Locker locker) {
this.locker = locker;
}
public synchronized void tryToDeadlock() {
String unused = locker.toString();
}
@Override
@SuppressWarnings("CatchAndPrintStackTrace")
public synchronized String toString() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
return super.toString();
}
}
final Locker one = new Locker();
final Locker two = new Locker();
one.setLocker(two);
two.setLocker(one);
// Deadlock expected here:
for (int i = 0; i < 100; i++) {
SwingUtilities.invokeLater(one::tryToDeadlock);
two.tryToDeadlock();
}
}
// If we don't do our post-dispatch activity in a finally block, we'll
// report bogus hangs.
private static void runExceptionTest(final JFrame frame) {
JButton button = new JButton("Throw Exception");
button.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// This shouldn't cause us to report a hang.
throw new IllegalStateException("Nobody expects the Spanish Inquisition!");
}
});
frame.add(button);
}
// A demonstration of nested calls to dispatchEvent caused by SequencedEvent.
private static void runFocusTest(final JFrame frame) {
final JDialog dialog = new JDialog(frame, "Non-Modal Dialog");
dialog.add(new JLabel("Close me!"));
dialog.pack();
dialog.setLocationRelativeTo(frame);
dialog.addWindowFocusListener(
new WindowAdapter() {
@Override
public void windowGainedFocus(WindowEvent e) {
System.out.println("FocusTest.windowGainedFocus");
// If you don't cope with nested calls to dispatchEvent, you won't detect this.
// See java.awt.SequencedEvent for an example.
sleep(2500);
}
});
JButton button = new JButton("Show Non-Modal Dialog");
button.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.setVisible(true);
}
});
frame.add(button);
}
// A demonstration of the problems of dealing with modal dialogs.
private static void runModalTest(final JFrame frame, final boolean shouldSleep) {
System.out.println(shouldSleep ? "Expect hangs!" : "There should be no hangs...");
JButton button = new JButton("Show Modal Dialog");
button.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (shouldSleep) {
sleep(2500); // This is easy.
}
JDialog dialog = new JDialog(frame, "Modal dialog", /* modal= */ true);
dialog.setLayout(new FlowLayout());
dialog.add(new JLabel("Close this dialog!"));
final JLabel label = new JLabel(" ");
dialog.add(label);
dialog.pack();
dialog.setLocation(frame.getX() - 100, frame.getY());
// Make sure the new event pump has some work to do, each unit of which is insufficient
// to cause a hang.
new Thread(
() -> {
for (int i = 0; i <= 100000; ++i) {
final int value = i;
EventQueue.invokeLater(() -> label.setText(Integer.toString(value)));
}
})
.start();
dialog.setVisible(true);
if (shouldSleep) {
sleep(
2500); // If you don't distinguish different stack traces, you won't report this.
}
}
});
frame.add(button);
}
@SuppressWarnings("CatchAndPrintStackTrace")
private static void sleep(long ms) {
try {
System.out.println("Sleeping for " + ms + " ms on " + Thread.currentThread() + "...");
Thread.sleep(ms);
System.out.println("Finished sleeping...");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
private Tests() {
}
}