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