HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

In this month's column I'll show you how to re-route the standard input and output streams for more versatile applets, applications (and other Java executable types). The impetus for this technique was pretty much born when Microsoft's Internet Explorer first came out. You see, before Internet Explorer there was really only one Web browser that could do Java applets and was widely distributed throughout the world of Web surfers: Netscape's Navigator 2.0. An applet programmer's life was simple then: target Navigator and debug using Navigator for commercial-quality applets. (The JDK's AppletViewer was also available, but for widespread distribution you really needed to target Navigator and use it as the benchmark for compatibility.)

That version of the Navigator had a Java Output window you could bring up. This window displayed everything written to all applets' standard output stream, which is System.out. This window was generally employed to display debugging information, much like printf is often used in C programs.

Then came Internet Explorer. Internet Explorer did not have such a simple mechanism for viewing an applet's standard output stream. So, while it was still easy to display debugging information in the Navigator, the other Web browser with widespread distribution was a little bit harder to debug with and test for compatibility. That is, an applet had to throw up its own message window or write information back to a server or use some other such special reporting mechanism to give you interactive feedback. (I am, of course, talking about running an applet outside of an active debugging session, like you can when using Visual J++ and Internet Explorer in conjunction.)

I realized at this time that gone were the days when you could simply write System.out.println(My X variable is: + x) and be able to view that output easily while an applet was running. Many people also realized the same was true in another Java runtime environment - when running a Java application without a console window. The Win32 JDK, for example, ships with a version of the standalone compiler named javaw. This interpreter runs without a console window, which is great because you don't have a big black window popping up and cluttering an application's interface. The drawback is that the console window is usually where the standard output and standard error streams are displayed. No console window means neither stream is viewable.

So now there are two environments where standard I/O streams are essentially not available: applets (in Internet Explorer) and non-console Java applications. And there are many more such runtime environments: Servlets, Java implementations of ActiveX or CORBA objects and basically any embedded runtime environment.

By simply replacing the OutputStream automatically given in System.out, however, you can construct your own standard output window that's always available, no matter what the runtime environment. Replacing the System.out object is really very easy:

// Replacing System.out
void replaceStandardOut(OutputStream newOut) {
System.out = newOut;
}

That is, the System class members in, out and err are just public object references to stream objects. Set these member references to other objects and you've effectively re-routed your standard stream elsewhere.

Listing 1 shows a simple but useful example of how to employ standard stream re-routing. In Listing 1 is the main() method of a standalone application. We can imagine this application to process an input stream and do something with it (write a corresponding output stream or follow the directions in the input stream to perform some operations or whatever). What's neat about Listing 1 is that the input can come from either a file or from standard input (the console). The presence of a command-line argument indicates inut comes from a file. In that case, System.in is replaced with a FileInputStream object built from the first command-line argument. No other change in the program's code is needed to handle the alternative sources of input.

Similarly, Listing 2 is a program that re-routes the standard output stream to a file if a command-line argument is present. Otherwise, System.out is left alone and will probably be displayed in a console window, at least if a consoled Java interpreter is used anyway.

But the original problem I talked about is applet feedback and, more generally, immediate feedback when a standard output or error stream display is not available. To solve this problem, I created a little class shown in Listing 3 called the StandardOutputFilterStream. The job of this class is always to re-route the standard output and error streams to alternative sources. The static initializer block, shown at the top of the class listing, ensures that System.out and System.err are immediate re-routed when the StandardOutputFilterStream class is loaded. By default they are re-routed to themselves, which is a no-op. By calling the class static methods setStandardOutput() and setStandardError(), these two standard streams are immediately re-routed to alternative streams.

Not shown (for lack of space) is a class that could display any output stream in a standalone top-level frame window. Such a class is very easy to create if you use this trick: Let the only child of the display frame be a List object. Whenever a new line is written to the stream, append the entire corresponding line of text to the List object. For proper display, the Frame uses a BorderLayout object as its layout manager and the List object occupies the Center position in the layout.

Using such a display window means every applet will automatically have its own Java Console window, so anything written to System.out will appear in the window. That is, you could easily hook up a stream-displayer window to the StandardOutputFilterStream class given in Listing 3. In other non-console environments, the standard output streams can also be displayed using this StandardOutputFilterStream class. If you don't want to, you need never window your standard output streams again, in any environment.

About the Author
Brian Maso is a programming consultant working out of Portland, OR. He is the co-author of The Waite Group Press's upcoming release, "The Java API SuperBible." Before Java, he spent five years corralled in the MS Windows branch of programming, working for such notables as the Hearst Corp., First DataBank and Intel. Readers are encouraged to contact Brian via e-mail with any comments or questions.

	

Listing 1.
 
// Optional re-routing of standard input 
// stream based on command-line args 
public static void main(String[] astrArgs) { 
  if(astrArgs.length != 0) 
    try { 
      System.in = 
          new FileInputStream(astrArgs[0]); 
    } catch (IOException ioe) { 
      // Forget it or report error 
    } 
  // Now, just process System.in 

} 

Listing 2.
 
// Optional re-routing of standard output 
public static void main(String[] astrArgs) { 
  if(astrArgs.length != 0) 
    try { 
      System.out = 
          new FileOutputStream(astrArgs[0]); 
    } catch (IOException ioe){ 
      // Forget it or report error 
    } 

  // Now, just write output to 
  // System,out. 

} 
  

Listing 3.
 
// Call setStandardOutput() or setStandardInput() 
// to re-route standard streams. 
public class StandardOutputFilterStream 
    extends FilterOutputStream { 

  static { 
    System.out = 
        new StandardOutputFilterStream( 
        System.out); 
    System.err = 
        new StandardOutputFilterStream( 
        System.err); 
  } 

  protected StandardOutputFilterStream( 
      OutputStream out) { 
    super(out); 
  } 

  public void setStandardOutput( 
      OutputStream out) { 
    System.out = 
        new StandardOutputFilterStream(out); 
  } 

  public void setStandardError( 
      OutputStream err) { 
    System.err =  
        new StandardOutputFilterStream(err); 
  } 
} 


 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: info@sys-con.com

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.