import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


/**
* Invoke MSwingApplication to see a demo of how deadlock can occur while using join.
**/
public class MSwingApplication {
    /**
     * Sets up the buttons!!!
     **/
    public Component createComponents()
    {
        JButton goButton = new JButton("Launch Thread");
        goButton.setMnemonic(KeyEvent.VK_L);
        goButton.addMouseListener(new MouseAdapter()
        {
            public void mouseClicked(MouseEvent e) {
                WorkerThread _wt = new WorkerThread();
                _wt.start();
                JOptionPane.showMessageDialog(null, "Returned from WorkerThread invocation to main event thread");
            }
        });

        JButton autoButton = new JButton("Launch Thread and Automate");
        autoButton.setMnemonic(KeyEvent.VK_A);
        autoButton.addMouseListener(new MouseAdapter()
        {
            public void mouseClicked(MouseEvent e)
            {
                Thread _localThread = new Thread()
                {
                    public void run()
                    {
                        try
                        {
                            System.out.println("Creating Robot");
                            Robot _robot = new java.awt.Robot();
                            _robot.setAutoDelay(250);
                            System.out.println("Move Robot");

                            _robot.mouseMove(60, 60);
                            System.out.println("Left mouse click");
                            _robot.mousePress(InputEvent.BUTTON1_MASK);
                            _robot.mouseRelease(InputEvent.BUTTON1_MASK);
                            _robot.delay(500);

                            _robot.mouseMove(512, 410);
                            _robot.delay(750);
                            System.out.println("Left Mouse click");
                            _robot.mousePress(InputEvent.BUTTON1_MASK);
                            _robot.mouseRelease(InputEvent.BUTTON1_MASK);

                            _robot.delay(250);
                            System.out.println("Left Mouse Click");
                            _robot.mousePress(InputEvent.BUTTON1_MASK);
                            _robot.mouseRelease(InputEvent.BUTTON1_MASK);
                        } // try
                        catch(Exception _e)
                        {
                          _e.printStackTrace();
                        } // catch
                    } // run
                }; // new Thread
                _localThread.start();
            } // mouseClicked
        } // new MouseAdapter
        );// addMouseListener


        JButton waitButton = new JButton("Launch Thread And Wait");
        waitButton.setMnemonic(KeyEvent.VK_W);
        waitButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                WorkerThread _wt = new WorkerThread();
                try
                {
                    _wt.start();
                    _wt.join();
                    JOptionPane.showMessageDialog(null, "I never get here because of the join");
                }
                catch(Exception _e)
                {
                  _e.printStackTrace();
                }
            }
        });


        /*
         * An easy way to put space between a top-level container
         * and its contents is to put the contents in a JPanel
         * that has an "empty" border.
         */
        JPanel pane = new JPanel();
        pane.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30));
        pane.setLayout(new GridLayout(0, 1));
        pane.add(goButton);
        pane.add(autoButton);
        pane.add(waitButton);

        return pane;
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(
                UIManager.getCrossPlatformLookAndFeelClassName());
        } catch (Exception e) { }

        //Create the top-level container and add contents to it.
        JFrame frame = new JFrame("ThreadScenario");
        MSwingApplication app = new MSwingApplication();
        Component contents = app.createComponents();
        frame.getContentPane().add(contents, BorderLayout.CENTER);

        //Finish setting up the frame, and show it.
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        frame.pack();
        frame.setVisible(true);
    }
}



/**
* WorkerThread class can cause a deadlock when called by the main AWT event thread.
* See class MSwingApplication for a demonstration.
**/
class WorkerThread extends Thread
{
    WorkerThread()
    {
        super();
    }

    public void run()
    {
        System.out.println("Entering WorkerThread run method");
        try
        {
            sleep(1000);
        }
        catch(Exception _e)
        {
          _e.printStackTrace();
        }

        //This dialog can cause deadlock if the main event thread is halted at a join().
        //The same problem appears if invokeAndWait is called.  Anything which needs the
        //main event thread to complete can cause deadlock.
        //If no join is called, everything works great.
        JOptionPane.showMessageDialog(null, "This message dialog deadlocks the app if you press the wait button");
        System.out.println("Exiting WorkerThread run method");
    }
}




