001: /*
002: * @(#)IOThreadRunner.java 1.0.0 11/17/2000 - 13:41:07
003: *
004: * Copyright (C) 2000,,2003 2002 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.util.thread.v1;
028:
029: import java.io.IOException;
030: import java.io.InputStream;
031: import java.io.OutputStream;
032:
033: /**
034: * Loops, reading from the input stream and writes to the output stream.
035: *
036: *
037: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
038: * @since November 17, 2000
039: * @version $Date: 2003/02/10 22:52:48 $
040: * @see LoopThread
041: */
042: public class IOThreadRunner {
043: private static final int BUFFER_SIZE = 4096;
044: private InputStream is;
045: private OutputStream os;
046: private byte[] buffer = new byte[BUFFER_SIZE];
047: private LoopThread lt;
048: private IOException exception;
049: private boolean closeInputOnEOF = false;
050: private boolean closeOutputOnEOF = false;
051:
052: private Runnable ltRunner = new Runnable() {
053: public void run() {
054: try {
055: int read = is.read(buffer, 0, BUFFER_SIZE);
056: if (read > 0) {
057: /*
058: System.out.print("[IOThreadRunner: read: {");
059: System.out.write( buffer, 0, read );
060: System.out.println("} ]");
061: */
062: os.write(buffer, 0, read);
063: } else {
064: //System.out.print("[IOThreadRunner: EOF]");
065: reachedEOF();
066: }
067: } catch (IOException e) {
068: registerException(e);
069: }
070: }
071: };
072:
073: /**
074: * Create a new ThreadRunner, re-routing <tt>is</tt> data into the
075: * <tt>os</tt> stream.
076: */
077: public IOThreadRunner(InputStream is, OutputStream os) {
078: this (new LoopThread(), is, os);
079:
080: this .lt.setDaemon(true);
081: this .lt.setSleepTimeMillis(0L);
082: }
083:
084: /**
085: * Create a new ThreadRunner, re-routing <tt>is</tt> data into the
086: * <tt>os</tt> stream, but uses the initialization of the given
087: * LoopThread. Note that <tt>lt</tt> must not be a running thread.
088: */
089: public IOThreadRunner(LoopThread lt, InputStream is, OutputStream os) {
090: this .lt = lt;
091: lt.setRunnable(ltRunner);
092: this .is = is;
093: this .os = os;
094: }
095:
096: /**
097: * Retrieves the most recent exception that occured, if any. If no
098: * exception happened, then it returns <tt>null</tt>.
099: */
100: public IOException getException() {
101: return this .exception;
102: }
103:
104: /**
105: * By setting this to <tt>true</tt> the runner will close the InputStream
106: * once a Stop signal has been encountered.
107: */
108: public void setCloseInputOnStop(boolean on) {
109: this .closeInputOnEOF = on;
110: }
111:
112: /**
113: * By setting this to <tt>true</tt> the runner will close the OutputStream
114: * once a Stop signal has been encountered.
115: */
116: public void setCloseOutputOnStop(boolean on) {
117: this .closeOutputOnEOF = on;
118: }
119:
120: /**
121: * Retrieves the LoopThread instance that manages the operation. You
122: * can use this instance for setting up the thread (such as setting
123: * priority and daemon status).
124: */
125: public LoopThread getThread() {
126: return this .lt;
127: }
128:
129: /**
130: * Retrieves the output stream that the input is redirected to.
131: */
132: public OutputStream getOutputStream() {
133: return this .os;
134: }
135:
136: /**
137: * @return <tt>true</tt> if the thread is alive and reading the
138: * stream, or <tt>false</tt> if it is not reading.
139: */
140: public boolean isReading() {
141: return this .lt.isAlive();
142: }
143:
144: /**
145: * Starts the stream reading.
146: */
147: public void start() {
148: this .lt.start();
149: }
150:
151: /**
152: * Stops the thread from reading.
153: */
154: public void stop() throws IOException {
155: if (this .closeInputOnEOF) {
156: this .is.close();
157: }
158: if (this .closeOutputOnEOF) {
159: this .os.close();
160: }
161: this .lt.stop();
162: }
163:
164: /**
165: * Post an exception, and stop the reading.
166: */
167: protected void registerException(IOException ioe) {
168: this .exception = ioe;
169: try {
170: stop();
171: } catch (IOException ex) {
172: // ignore
173: }
174: }
175:
176: /**
177: * Stop the reading and void out any exceptions.
178: */
179: protected void reachedEOF() {
180: this .exception = null;
181: try {
182: stop();
183: } catch (IOException ioe) {
184: this.exception = ioe;
185: }
186: }
187: }
|