Received: from PACIFIC-CARRIER-ANNEX.MIT.EDU by po10 (5.61/4.7) id AA28738; Tue, 11 Jul 00 18:37:10 EDT Received: from hermes.javasoft.com by MIT.EDU with SMTP id AA15665; Tue, 11 Jul 00 18:38:40 EDT Received: (from nobody@localhost) by hermes.java.sun.com (8.9.3+Sun/8.9.1) id WAA04738; Tue, 11 Jul 2000 22:34:45 GMT Date: Tue, 11 Jul 2000 22:34:45 GMT Message-Id: <200007112234.WAA04738@hermes.java.sun.com> X-Authentication-Warning: hermes.java.sun.com: Processed from queue /bulkmail/data/teri_71/mqueue5 X-Mailing: 227 From: JDCTechTips@sun.com Subject: JDC Tech Tips - July 11, 2000 To: JDCMember@sun.com Reply-To: JDCTechTips@sun.com Errors-To: bounced_mail@hermes.java.sun.com Precedence: junk Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Mailer: Beyond Email 2.2 J D C T E C H T I P S TIPS, TECHNIQUES, AND SAMPLE CODE WELCOME to the Java Developer Connection(sm) (JDC) Tech Tips, July 11, 2000. This issue covers: * Using Shutdown Hooks * Automating GUI Programs With java.awt.Robot These tips were developed using Java(tm) 2 SDK, Standard Edition, v 1.3. You can view this issue of the Tech Tips on the Web at http://developer.java.sun.com/developer/TechTips/2000/tt0711.html - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - USING SHUTDOWN HOOKS Suppose that you're writing an application, and you'd like to gain control when the application shuts down. You might want to do this in order to close files that are open, for example, close a log file that the application has written to. One way to gain control is simply to have a shutdown method that you call before calling exit: callShutdown(); System.exit(0); This approach works if your application terminates only in one place, that is, System.exit is called only one place, or if you specify callShutdown everywhere that you exit. This approach also requires that you catch all exceptions that are thrown, which otherwise would terminate the program abnormally. In JDK 1.3 there's another way to handle shutdown: using shutdown hooks. A shutdown hook is an initialized thread that has not yet been executed. In other words, a shutdown hook is an object of a class derived from the Thread class, with a run method that is called to perform whatever actions you want. You register this object with the Java(tm) Virtual Machine (JVM)*. Here's an example: import java.io.*; public class ShutdownDemo { private FileWriter fw_log; private BufferedWriter bw_log; // constructor that opens the log file public ShutdownDemo() throws IOException { fw_log = new FileWriter("log.txt"); bw_log = new BufferedWriter(fw_log); // register the shutdown hook Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { endApp(); } });; } // do some application processing and write to the log file public void processApp1() throws IOException { bw_log.write("testing"); bw_log.newLine(); } // do some application processing resulting in an exception public void processApp2() { throw new RuntimeException(); } // close the log file public void endApp() { try { bw_log.close(); } catch (IOException e) { System.err.println(e); } } public static void main(String args[]) throws IOException { // create an application object ShutdownDemo demo = new ShutdownDemo(); // do some processing demo.processApp1(); // do some more processing that results in an exception demo.processApp2(); } } This application creates an instance of the ShutdownDemo class, representing an application. The constructor for the class opens a log file, using FileWriter and BufferedWriter. ShutdownDemo then calls processApp1. In its processing, processApp1 writes an entry to the log file. Then processApp2 is called. It throws an exception that is not caught by the application. Normally, this exception would terminate the application; the log file entry previously written would be lost because the output is sitting in a buffer which has not been flushed to disk. But in this demo the output is not lost. This is because the application registers a shutdown hook by saying: Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { endApp(); } });; Notice the use of an anonymous inner class. Here an instance of an unnamed class derived from Thread is created, and a run method that calls endApp is defined for the class. All of this means that when the application is about to terminate, the JVM starts the thread representing by the passed-in thread object. When the thread starts, the run method is called. The run method calls endApp, which closes the log file. This flushes the output buffer. To underscore the effect of the shutdown hook, comment out the addShutdownHook lines in ShutdownDemo. You'll see that the log file is empty when the program terminates. You can register multiple shutdown hooks. In this case, each thread that represents a hook is started in an unspecified order, and the various threads run simultaneously. You cannot register or unregister a shutdown hook after the shutdown sequence has started. Doing so results in an IllegalStateException. Because shutdown hooks run as threads, you must use thread-safe programming techniques. Otherwise you risk having threads interfere with each other. Also, it's wise to design your application for simple and fast shutdown processing. For example, you might run into trouble if your application uses services during shutdown that are themselves in the processing of being shut down. There are cases where shutdown processing does not happen even if you have registered shutdown hooks. One example is corrupted native methods, for example, when you dereference a null pointer in C code. This feature is somewhat similar to the atexit library function in C/C++. For further information about shutdown hooks, see: http://java.sun.com/j2se/1.3/docs/guide/lang/enhancements.html#hooks. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AUTOMATING GUI PROGRAMS WITH JAVA.AWT.ROBOT Imagine that you have a Java GUI program written using the AWT and Swing libraries, and you'd like to automate the program. For example, you'd like to automatically supply GUI input events from the keyboard and mouse to the program. In this way, the program could operate without user intervention. This type of automation might be useful for testing purposes, or to produce a self-running demo program. java.awt.Robot is a new class in JDK 1.3, designed to handle this type of automation. It's a way to automatically feed input events to a program. The events are generated in the native input queue of the platform, as if they had actually been generated by the user. For example, using java.awt.Robot, you can generate an event that is equivalent to a user moving the mouse to particular (X,Y) coordinates on the screen. Here's an example of how you can use this class: import java.awt.*; import java.awt.event.*; import javax.swing.*; public class RobotDemo { public static void main(String args[]) throws AWTException { // set up frames and panels JFrame frame = new JFrame("RobotDemo"); JPanel panel = new JPanel(); panel.setLayout(new GridLayout(3, 1)); // set up fields, labels, and buttons final JTextField field = new JTextField(10); final JLabel lab = new JLabel(); field.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String s = "Length: " + field.getText().length(); lab.setText(s); } }); JButton button = new JButton("Exit"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); // add components to panel and display panel.add(field); panel.add(lab); panel.add(button); frame.getContentPane().add(panel); frame.setSize(200, 150); frame.setLocation(200, 200); frame.setVisible(true); // create a robot to feed in GUI events Robot rob = new Robot(); // enter some keystrokes int keyinput[] = { KeyEvent.VK_T, KeyEvent.VK_E, KeyEvent.VK_S, KeyEvent.VK_T, KeyEvent.VK_I, KeyEvent.VK_N, KeyEvent.VK_G }; rob.delay(1000); rob.keyPress(KeyEvent.VK_SHIFT); field.requestFocus(); for (int i = 0; i < keyinput.length; i++) { rob.keyPress(keyinput[i]); rob.delay(1000); } rob.keyRelease(KeyEvent.VK_SHIFT); rob.keyPress(KeyEvent.VK_ENTER); // move cursor to Exit button Point p = button.getLocationOnScreen(); rob.mouseMove(p.x + 5, p.y + 5); rob.delay(2000); // press and release left mouse button rob.mousePress(InputEvent.BUTTON1_MASK); rob.delay(2000); rob.mouseRelease(InputEvent.BUTTON1_MASK); } } The demo sets up a panel containing an input field, a label, and an Exit button. This part of the demo is typical of many Swing applications. Then the demo creates a Robot object, and feeds into it a series of keystrokes. These keystrokes mimic keys typed by a user, that is, the keys T, E, S, T, I, N, and G. There is a delay of 1000 milliseconds between keystrokes; this helps present the animation more clearly. The shift key is held down throughout, so that the letters are entered as capitals. At the end of the text input, Enter is specified. This causes the length of the input to be echoed in the label field. Then the mouse cursor is moved to the Exit button, and the left mouse button is pressed and released. This terminates the program. Notice that virtual keycodes are used to enter keystrokes; keycodes are not the same as Java characters. KeyEvent.VK_A corresponds to pressing the unshifted 'A' key on a keyboard. If you specify 'A' or 'a' instead of KeyEvent.VK_A, you get unexpected results. Also note that the documentation for Robot says that some platforms require special privileges to access low-level input control. One specific case is X Windows, which requires the XTEST 2.2 standard extension. For further information about java.awt.Robot, see http://java.sun.com/j2se/1.3/docs/api/java/awt/Robot.html. For further information about key events, see http://java.sun.com/j2se/1.3/docs/api/java/awt/event/KeyEvent.html. For further information about mouse events, see http://java.sun.com/j2se/1.3/docs/api/java/awt/event/MouseEvent.html. . . . . . . . . . . . . . . . . . . . . . . . - NOTE The names on the JDC mailing list are used for internal Sun Microsystems(tm) purposes only. To remove your name from the list, see Subscribe/Unsubscribe below. - FEEDBACK Comments? Send your feedback on the JDC Tech Tips to: jdc-webmaster@sun.com - SUBSCRIBE/UNSUBSCRIBE The JDC Tech Tips are sent to you because you elected to subscribe when you registered as a JDC member. To unsubscribe from JDC email, go to the following address and enter the email address you wish to remove from the mailing list: http://developer.java.sun.com/unsubscribe.html To become a JDC member and subscribe to this newsletter go to: http://java.sun.com/jdc/ - ARCHIVES You'll find the JDC Tech Tips archives at: http://developer.java.sun.com/developer/TechTips/index.html - COPYRIGHT Copyright 2000 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA. This document is protected by copyright. For more information, see: http://developer.java.sun.com/developer/copyright.html This issue of the JDC Tech Tips is written by Glen McCluskey. JDC Tech Tips July 11, 2000 * As used in this document, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.