001 // Copyright 2000,2004 Crispin Perdue <cris@perdues.com>
002 //
003 // This is free software, and comes with ABSOLUTELY NO WARRANTY.
004 // You may distribute it under the terms of the Library GNU Public License
005 // Version 2.
006
007 package com.perdues;
008
009 import java.util.logging.Logger;
010 import java.util.logging.Level;
011 import java.io.Reader;
012 import java.io.Writer;
013 import java.io.IOException;
014 import java.io.InputStreamReader;
015 import java.io.OutputStreamWriter;
016
017 /**
018 Copies from the Reader to the Writer until it reaches the end of the
019 InputStream or throws an Exception. This class provides "glue" when
020 you need to supply the data from a Reader to a Writer. Instances can
021 be configured to close the Writer upon thread termination. Normally
022 they do not close the Writer, so you can concatenate outputs and use
023 System.out or System.err for output. If the Reader's underlying
024 InputStream is interruptible, you can break out of a read and
025 terminate this thread by interrupting it.
026 */
027 public class CharPump extends Thread {
028
029 /**
030 Creates a CharPump that will copy the Reader to the Writer until it
031 reaches the end of the Reader or throws an Exception. This will
032 terminate on a thread interrupt if the current I/O operation
033 responds to the interrupt. You will need to call the
034 <tt>start</tt> method to make it go. Marks the new thread as a
035 daemon so its existence cannot stop the JVM from exiting.
036 */
037 public CharPump(Reader in, Writer out) {
038 this.in = in;
039 this.out = out;
040 setDaemon(true);
041 }
042
043
044 /**
045 If this thread terminated because of a Throwable,
046 it makes the value available through this method.
047 */
048 public synchronized Throwable getExitCause() {
049 return exitCause;
050 }
051
052
053 /**
054 Setting closeOnExit causes this to reliably close its Writer
055 when the thread terminates. It is initially not set.
056 */
057 public void setCloseOnExit(boolean request) {
058 closeOnExit = request;
059 }
060
061
062 /**
063 Returns this CharPump's closeOnExit status.
064 */
065 public boolean isCloseOnExit() {
066 return closeOnExit;
067 }
068
069
070 /**
071 The thread automatically runs this method. As usual for subclasses
072 of Thread, this is not intended to be invoked directly by client
073 code, use <tt>start</tt> instead.
074 */
075 public void run() {
076 char[] buf=new char[1024];
077 try {
078 while (true) {
079 int n=in.read(buf,0,buf.length);
080 if (n<0) break;
081 out.write(buf,0,n);
082 out.flush();
083 }
084 } catch (Throwable ex) {
085 exitCause = ex;
086 if (ex instanceof ThreadDeath) {
087 throw (ThreadDeath)ex;
088 }
089 } finally {
090 logger.log(Level.FINE, "terminated {0}", this);
091 if (closeOnExit) {
092 try {
093 out.close();
094 } catch(IOException ex) {}
095 }
096 }
097 }
098
099
100 /** COMMENTED OUT main (for testing)
101 public static void main(String[] args) {
102 CharPump p = new CharPump(new InputStreamReader(System.in),
103 new OutputStreamWriter(System.out));
104 p.start();
105 try { Thread.sleep(30*1000); } catch(InterruptedException ex) {}
106 p.interrupt();
107 try { p.join(); } catch(InterruptedException ex) {}
108 }
109 */
110
111 private boolean closeOnExit = false;
112
113 private Throwable exitCause = null;
114
115 private Reader in;
116 private Writer out;
117
118 private static Logger logger =
119 Logger.getLogger(CharPump.class.getName());
120
121 }