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 }