A Console for Output Streams
By Timothy Prinzing
The
JavaTM programming language's
I/O package provides a large collection of classes that support
different kinds of input/output streams, such as streams that are
bound to files, buffered streams, and streams that support special
operations like simple parsing. Most commonly, these classes are
used for reading and writing files, and for reading and writing
the user's console terminal.
The console terminal is usually the display window associated with
a Java programming language process. For instance, if the user starts
a Java application from a UNIX shell window, that window becomes
the console.
Sometimes the console isn't nearly so convenient. When an applet
is run in a browser such as Netscape Navigator, for example, the
console is a special write-only window that isn't shown by default.
In this article, we'll explain how to write a new Swing class,
called "ConsolePane," that displays one or more output streams.
The ConsolePane class can be used to create a component, much like
a UNIX or MS-DOS shell window, that can parse commands typed in
by a user and can display the output generated by the subprocesses
carrying out those commands.
The ConsolePane Class
At the end of the article, there's source code for an example program
named CommandConsole. When you run the program, it displays a console
window that looks like this:
In the next section, we'll show how to
connect streams to Swing text components. Then, in the section titled
"Displaying Output from a Process,"
we'll show how to define the ConsolePane class.
Connecting an OutputStream
to a Swing Document
The Swing text components delegate the responsibility for managing
the text they display to a separate model called a Document.
Swing provides Document classes for strings and for HTML and RTF
files. To create a Document that displays an output stream, we'll
define a new OutputStream class that contains a Document:
public class DocumentOutputStream extends OutputStream {
private Document doc;
public DocumentOutputStream(Document doc) {
this.doc = doc;
}
public void write(int b) throws IOException {
write(new Byte[]{b}, 0, 1);
}
public void write(byte b[], int off, int len) throws IOException {
try {
doc.insertString(doc.getLength(),
new String(b, off, len), null);
}
catch (BadLocationException ble) {
throw new IOException(ble.getMessage());
}
}
}
All the OutputStream methods eventually just call the three-argument
write() method -- and we've overridden that to call
Document.insertString() in a way that just appends
the incoming text to the end of the Document.
The Java I/O package includes another class like OutputStream
called Writer . Both Reader and Writer
were introduced in the 1.1 release of Java to address some shortcomings
in the corresponding Stream base classes. The implementation of
DocumentWriter class is very similar to DocumentOutputStream.
Here's a simple example that displays a DocumentOutputStream in
a Swing TextPane (the HelloWorld.java
and DocumentOutputStream.java
files contain the complete source code for this example):
JTextArea textArea = new JTextArea();
Document doc = textArea.getDocument();
PrintStream out = new PrintStream(new DocumentOutputStream(doc));
out.println("Hello World");
Displaying Output
from a Process
The Java Runtime class can be used to create a new native subprocess
that will execute asynchronously. Each process object has two output
streams: one for ordinary output and one for errors. The ConsolePane
class creates threads that read these streams, one line at a time,
and then copies the lines to a PrintStream that's connected to a
DocumentOutputStream as in the previous section. The Swing Document
classes are thread-safe, so many subprocesses can safely write to
the console.
The workhorse of the ConsolePane class is the showProcessOutput()
method. It starts the threads to read a processes normal and error
output streams an then connects them to the Document that displays
all output. An example application, called CommandConsole, adds
a text field for the user to enter commands and creates subprocesses
for each line entered. To the right of the text field, there's a
button that stops the current process.
Here are the source files for the CommandConsole application:
The console_examples.zip
file contains all these source files, plus object code and resources.
WARNING:
To compile and run the CommandConsole program, you'll need
the most recent version of Swing because it fixes a number of
bugs related to concurrency. More specifically, you'll need Swing
Version 1.1.1 beta 1 or JDK Version 1.2.1. (The latter was not
available when this article went online, but should be available
soon.)
|