Recipe 14.9 Getting Program Output into a Window


You want to capture an input/output stream and display it in a text field.


Use an interconnected pair of piped streams and a Thread to read from the input half, and write it to the text area. You may also want to redirect System.out and System.err to the stream; see Recipe 10.9.


PipedInputStream and PipedOutputStream provide two streams (see "Streams and Readers/Writers" at the beginning of Chapter 10) that are connected together by a buffer and are designed to provide communication between multiple threads (see the Introduction to Chapter 24).

As you'll see in Chapter 19, I am fairly aggressive in the pursuit of SPAM perpetrators. I have a program called TestOpenMailRelay , derived from the mail sender in Recipe 19.2, that I use to test whether remote servers are willing to accept mail from unknown third parties and forward it as their own. Example 14-5 is the GUI for that program; both this and the main program are online in the email directory.

In the constructor, I arrange for the main class to write to the PipedOutputStream; the call to TestOpenMailRelay.process( ) passing the ps argument arranges this. That method writes its own output to the stream in addition to assigning standard output and standard error, so we should see anything it tries to print. To avoid long (possibly infinitely long!) delays, I start an additional thread to read from the pipe buffer. Figure 14-8 shows three windows: the program output window (the goal of this whole exercise), a terminal window from which I copied the IP address (some parts of the text in this window have been deliberately obfuscated), and another command window in which I started the GUI program running.

Figure 14-8. TestOpenMailRelayGUI in action

Example 14-5.
import java.awt.*; import java.awt.event.*; import javax.swing.*; import*; /** GUI for TestOpenMailRelay, lets you run it multiple times in one JVM  * to avoid startup delay.  *  * Starts each in its own Thread for faster return to ready state.  *  * Uses PipedI/OStreams to capture system.out/err into a window.  */ public class TestOpenMailRelayGUI extends JFrame {     public static void main(String unused[]) throws IOException {         new TestOpenMailRelayGUI( ).setVisible(true);     }     /** The one-line textfield for the user to type Host name/IP */     protected JTextField hostTextField;     /** The push button to start a test; a field so can disable/enable it. */     protected JButton goButton;     /** Multi-line text area for results. */     protected JTextArea results;     /** The piped stream for the main class to write into ""results" */     protected PrintStream ps;     /** The piped stream to read from "ps" into "results" */     protected BufferedReader iis;     /** This inner class is the action handler both for pressing      * the "Try" button and also for pressing <ENTER> in the text      * field. It gets the IP name/address from the text field      * and passes it to process( ) in the main class. Run in the      * GUI Dispatch thread to avoid messing the GUI. -- tmurtagh.      */     ActionListener runner = new ActionListener( ) {         public void actionPerformed(ActionEvent evt) {             goButton.setEnabled(false);             SwingUtilities.invokeLater(                 new Thread( ) {                     public void run( ) {                         String host = hostTextField.getText( ).trim( );                         ps.println("Trying " + host);                         TestOpenMailRelay.process(host, ps);                         goButton.setEnabled(true);                     }                 });         }     };     /** Construct a GUI and some I/O plumbing to get the output      * of "TestOpenMailRelay" into the "results" textfield.      */     public TestOpenMailRelayGUI( ) throws IOException {         super("Tests for Open Mail Relays");         PipedInputStream is;         PipedOutputStream os;         JPanel p;         Container cp = getContentPane( );         cp.add(BorderLayout.NORTH, p = new JPanel( ));         // The entry label and text field.         p.add(new JLabel("Host:"));         p.add(hostTextField = new JTextField(10));         hostTextField.addActionListener(runner);         p.add(goButton = new JButton("Try"));         goButton.addActionListener(runner);         JButton cb;         p.add(cb = new JButton("Clear Log"));         cb.addActionListener(new ActionListener( ) {             public void actionPerformed(ActionEvent evt) {                 results.setText("");             }         });         JButton sb;         p.add(sb = new JButton("Save Log"));         sb.setEnabled(false);         results = new JTextArea(20, 60);         // Add the text area to the main part of the window (CENTER).         // Wrap it in a JScrollPane to make it scroll automatically.         cp.add(BorderLayout.CENTER, new JScrollPane(results));         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);         pack( );            // end of GUI portion         // Create a pair of Piped Streams.         is = new PipedInputStream( );         os = new PipedOutputStream(is);         iis = new BufferedReader(new InputStreamReader(is, "ISO8859_1"));         ps = new PrintStream(os);         // Construct and start a Thread to copy data from "is" to "os".         new Thread( ) {             public void run( ) {                 try {                     String line;                     while ((line = iis.readLine( )) != null) {                         results.append(line);                         results.append("\n");                     }                 } catch(IOException ex) {                     JOptionPane.showMessageDialog(null,                         "*** Input or Output error ***\n" + ex,                         "Error",                         JOptionPane.ERROR_MESSAGE);                 }             }         }.start( );     } }

Java Cookbook
Java Cookbook, Second Edition
ISBN: 0596007019
EAN: 2147483647
Year: 2003
Pages: 409
Authors: Ian F Darwin

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: